1 //----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2007 by the FRESCOR consortium:
4 // Universidad de Cantabria, SPAIN
5 // University of York, UK
6 // Scuola Superiore Sant'Anna, ITALY
7 // Kaiserslautern University, GERMANY
8 // Univ. Politecnica Valencia, SPAIN
9 // Czech Technical University in Prague, CZECH REPUBLIC
11 // Thales Communication S.A. FRANCE
12 // Visual Tools S.A. SPAIN
13 // Rapita Systems Ltd UK
16 // See http://www.frescor.org
18 // The FRESCOR project (FP6/2005/IST/5-034026) is funded
19 // in part by the European Union Sixth Framework Programme
20 // The European Union is not liable of any use that may be
24 // based on previous work (FSF) done in the FIRST project
26 // Copyright (C) 2005 Mälardalen University, SWEDEN
27 // Scuola Superiore S.Anna, ITALY
28 // Universidad de Cantabria, SPAIN
29 // University of York, UK
31 // This file is part of FOSA (Frsh Operating System Abstraction)
33 // FOSA is free software; you can redistribute it and/or modify it
34 // under terms of the GNU General Public License as published by the
35 // Free Software Foundation; either version 2, or (at your option) any
36 // later version. FOSA is distributed in the hope that it will be
37 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
38 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 // General Public License for more details. You should have received a
40 // copy of the GNU General Public License along with FOSA; see file
41 // COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
42 // Cambridge, MA 02139, USA.
44 // As a special exception, including FOSA header files in a file,
45 // instantiating FOSA generics or templates, or linking other files
46 // with FOSA objects to produce an executable application, does not
47 // by itself cause the resulting executable application to be covered
48 // by the GNU General Public License. This exception does not
49 // however invalidate any other reasons why the executable file might be
50 // covered by the GNU Public License.
51 // -----------------------------------------------------------------------
52 //fosa_threads_and_signals.c
53 //==============================================
54 // ******** ****** ******** **********
55 // **///// /** ** **////// /** /**
56 // ** /** ** /** /** /**
57 // ******* /** ** /********* /**********
58 // **//// /** ** ////////** /**//////**
59 // ** /** ** /** /** /**
60 // ** /** ** ******** /** /**
61 // // /******/ //////// // //
63 // FOSA(Frescor Operating System Adaptation layer)
64 //================================================
66 #include "fosa_threads_and_signals.h"
67 #include "fosa_configuration_parameters.h"
73 #include <misc/error_checks.h>
76 * @defgroup threadandsignals Thread and Signals
79 * This module defines the functions that manipulate frsh_threads and
80 * frsh_signals inside FRSH implementation.
82 * Applications can refer to FRSH threads but they cannot create them
83 * directly, instead they must use frsh_thread_create*() which in turn
84 * use fosa_thread_create().
86 * For signals, we assume that the OS provides a direct mapping
87 * for frsh_signal_t and frsh_signal_info_t in the native interface.
92 //////////////////////////////////////////////////////////////////
93 // Storage of thread-specific keys
94 // - key_list is an array containing the keys
95 // - key_in_use is an array of booleans
96 // - key_lock is a mutex that locks the data structure
97 // while creating a new key
98 // - keys_initialized indicates whether the key_in_use array and
99 // the key_lock mutex are initialized or not; it is declared
100 // volatile as it may be accessed concurrently
101 //////////////////////////////////////////////////////////////////
103 static pthread_key_t key_list[FOSA_MAX_KEYS];
104 static bool key_in_use[FOSA_MAX_KEYS];
105 static pthread_once_t keys_initialized=PTHREAD_ONCE_INIT;
106 static pthread_mutex_t key_lock;
109 // Initialize the keys data structure
110 // This function should be called from pthread_once() to ensure
111 // one single initialization
114 pthread_mutexattr_t attr;
117 // initialize the key_in_use array and the mutex
118 for(i=0; i<FOSA_MAX_KEYS;i++) {
121 // Initialize the mutex
122 CHK(pthread_mutexattr_init(&attr));
123 // we use the priority inheritance protocol because we don't know which
124 // tasks will be using the mutex
125 CHK(pthread_mutexattr_setprotocol(&attr,PTHREAD_PRIO_INHERIT));
126 CHK(pthread_mutex_init(&key_lock,&attr));
127 CHK(pthread_mutexattr_destroy(&attr));
130 /*************************
131 * Thread identification
132 *************************/
135 * fosa_thread_equal()
137 * Compare two thread identifiers to determine if they refer to the
140 bool fosa_thread_equal(frsh_thread_id_t t1, frsh_thread_id_t t2)
142 return pthread_equal(t1,t2);
149 * Return the thread id of the calling thread
151 frsh_thread_id_t fosa_thread_self()
153 return pthread_self();
157 /*************************
158 * Thread creation and termination
159 *************************/
162 * fosa_thread_create()
164 * This function creates a new thread using the attributes specified
165 * in attr. If attr is NULL, default attributes are used. The new
166 * thread starts running immediately, executing the function specified
167 * by code, with an argument equal to arg. Upon successful return, the
168 * variable pointed to by tid will contain the identifier of the newly
169 * created thread. The set of signals that may be synchronously
170 * accepted is inherited from the parent thread.
172 * Returns 0 if successful; otherwise it returs a code error:
174 * EAGAIN: the system lacks the necessary resources to create a
175 * new thread or the maximum number of threads has been
178 * EINVAL: the value specified by attr is invalid (for instance,
179 * it has not been correctly initialized)
181 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
182 * possibly because of incorrect attributes, or because the
183 * requested minimum capacity cannot be guaranteed
186 int fosa_thread_create
187 (frsh_thread_id_t *tid, const frsh_thread_attr_t *attr,
188 frsh_thread_code_t code, void * arg)
190 return pthread_create(tid,attr,code,arg);
195 * Note: no thread termination primitive is provided. The termination
196 * of a thread will be notified by the system to the FRSH scheduler
197 * through the scheduler API
201 /**************************************************
202 * Thread-specific data
203 * (extended with access from a different thread)
205 * Several data items (pointers) may be associated with each thread
206 * Each item is identified through a key, an integer value between 0
207 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
208 * deallocating the memory area pointed to by the pointer
209 **************************************************/
214 * Create a new key for thread specific data.
216 * Prior to setting data in a key, we need ask the system to create
219 * @return 0 if successful \n
220 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
221 * FOSA_ENOMEM If there are no enough memory resources to
224 int fosa_key_create(int *key)
229 // initialize the keys data structure if needed
230 CHK(pthread_once(&keys_initialized, init_keys));
233 CHK(pthread_mutex_lock(&key_lock));
235 // find an unused key
236 for(i=0; i<FOSA_MAX_KEYS;i++) {
237 if (!key_in_use[i]) {
240 ret_value=pthread_key_create(&(key_list[i]),NULL);
245 // unlock the mutex before returning
246 CHK(pthread_mutex_unlock(&key_lock));
248 // all keys are in use; max keys reached
249 ret_value=FOSA_EINVAL;
259 * This destroys the key and isables its use in the system
261 * @return 0 if successful \n
262 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
264 int fosa_key_destroy(int key)
269 CHK(pthread_mutex_lock(&key_lock));
271 // destroy the key and mark it as available
272 ret_value=pthread_key_delete(key_list[key]);
274 key_in_use[key]=false;
277 // unlock the mutex before returning
278 CHK(pthread_mutex_unlock(&key_lock));
284 * fosa_thread_set_specific_data()
286 * Set thread-specific data
288 * For the thread identified by tid, the thread-specifid data field
289 * identified by key will be set to the value specified by value
291 * Returns 0 if successful; otherwise, an error code is returned
292 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
294 * Alternatively, in case of error the implementation is allowed to
295 * notify it to the system console and then terminate the FRSH
296 * implementation and dependant applications
298 int fosa_thread_set_specific_data
299 (int key, frsh_thread_id_t tid, const void * value)
301 return pthread_setspecific_for(key_list[key],tid,value);
305 * fosa_thread_get_specific_data()
307 * Get thread-specific data
309 * For the thread identified by tid, the thread-specifid data field
310 * identified by key will be copied to the variable pointed to by value
312 * Returns 0 if successful; otherwise, an error code is returned
313 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
315 * Alternatively, in case of error the implementation is allowed to
316 * notify it to the system console and then terminate the FRSH
317 * implementation and dependant applications
319 int fosa_thread_get_specific_data(int key, frsh_thread_id_t tid,
322 return pthread_getspecific_from(key_list[key],tid,value);
326 /******************************************************************
329 * This implementation of FRSH assumes an underlying fixed priority
330 * scheduler with priorities in a range, with a minimum and a
331 * maximumm, a number of priority levels with at least 31
332 * priorities. A larger number implies a larger priority. In systems
333 * in which the underlying scheduler uses the opposite convention, a
334 * mapping is automatically provided by the OS adaptation layer.
335 *******************************************************************/
338 * fosa_get_priority_max()
340 * Return the maximum priority value used in this implementation
342 int fosa_get_priority_max()
344 return sched_get_priority_max(SCHED_APP);
348 * fosa_get_priority_min()
350 * Return the minimum priority value used in this implementation
352 int fosa_get_priority_min()
354 return sched_get_priority_min(SCHED_APP);
358 * fosa_thread_attr_set_prio()
360 * Change the priority of a thread attributes object
362 * The priority of the thread attriutes object specified by attr is
363 * set to the value specified by prio. This function has no runtime
364 * effect on the priority, except when the attributes object is used
365 * to create a thread, when it will be created with the specified
368 * Returns 0 if successful, or the following error code:
369 * EINVAL: the specified priority value is not between the
370 * minimum and the maximum priorities defined in this
371 * FRSH implementation
372 * Alternatively, in case of error the implementation is allowed to
373 * notify it to the system console and then terminate the FRSH
374 * implementation and dependant applications
376 int fosa_thread_attr_set_prio(frsh_thread_attr_t *attr, int prio)
378 struct sched_param param;
380 param.sched_priority=prio;
381 return pthread_attr_setschedparam(attr,¶m);
385 * fosa_thread_attr_get_prio()
387 * Get the priority from a thread attributes object
389 * This function sets the variable pointed to by prio to the
390 * priority stored in the thread attributes object attr.
394 int fosa_thread_attr_get_prio
395 (const frsh_thread_attr_t *attr, int *prio)
397 struct sched_param param;
400 ret_value=pthread_attr_getschedparam(attr,¶m);
402 *prio=param.sched_priority;
408 * fosa_thread_set_prio()
410 * Dynamically change the priority of a thread
412 * The priority of the thread identified by tid is
413 * set to the value specified by prio.
415 * Returns 0 if successful, or the following error code:
416 * EINVAL: the specified priority value is not between the
417 * minimum and the maximum priorities defined in this
418 * FRSH implementation
419 * Alternatively, in case of error the implementation is allowed to
420 * notify it to the system console and then terminate the FRSH
421 * implementation and dependant applications
423 int fosa_thread_set_prio(frsh_thread_id_t tid, int prio)
425 struct sched_param param;
426 int policy, ret_value;
428 ret_value=pthread_getschedparam(tid,&policy,¶m);
429 if (ret_value!=0) return ret_value;
431 param.sched_priority=prio;
432 return pthread_setschedparam(tid,policy,¶m);
436 * fosa_thread_get_prio()
438 * Dynamically get the priority of a thread
440 * This function sets the variable pointed to by prio to the
441 * priority of the thread identified by tid
445 int fosa_thread_get_prio (frsh_thread_id_t tid, int *prio)
447 struct sched_param param;
448 int policy, ret_value;
450 ret_value=pthread_getschedparam(tid,&policy,¶m);
452 *prio=param.sched_priority;
459 /*******************************************************************
462 * Signals represent events that may be notified by the system, or
463 * sent explicitly by the application, and for which a thread may
464 * synchronously wait. Signals carry an associated piece of
465 * information (an integer or a pointer) and are queued until they are
466 * accepted. Signals are identified by an integer signal number (of
467 * the type frsh_signal_t) in the range FOSA_SIGNAL_MIN,
468 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
470 *******************************************************************/
473 * fosa_set_accepted_signals()
475 * Establish the set of signals that may be synchronously accepted
476 * by the calling thread
478 * The function uses the array of signal numbers specified by set,
479 * which must be of size equal to size
481 * Returns 0 if successful; otherwise it returns an error code:
482 * EINVAL: the array contains one or more values which are not
483 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
486 * Alternatively, in case of error the implementation is allowed to
487 * notify it to the system console and then terminate the FRSH
488 * implementation and dependant applications
490 int fosa_set_accepted_signals(frsh_signal_t set[], int size)
494 struct sigaction act;
496 // empty the signal set
497 CHKE(sigemptyset(&signalset));
499 // configure the signal action to make the signal a real-time
500 // signal that can be queued
501 act.sa_handler=SIG_DFL;
502 act.sa_mask=signalset;
503 act.sa_flags=SA_SIGINFO;
504 act.sa_sigaction=NULL;
506 // loop for all signals in set
507 for(i=0;i<size;i++) {
508 CHKE(sigaddset(&signalset,set[i]));
509 // Configure the signal so that it can be queued with data
510 CHKE(sigaction(set[i],&act,NULL));
512 return pthread_sigmask(SIG_BLOCK,&signalset,NULL);
516 * fosa_signal_queue()
520 * This function is used to explicitly send a signal with a specified
523 * The signal number specified by signal is sent together with the
524 * information specified by info, to the thread identified by
525 * receiver. In those implementations that do not support queueing a
526 * signal with information to a thread (such as POSIX), the signal may
527 * be sent to any thread that is waiting for this signal via
528 * fosa_signal_wait(). Portability can be ensured by having the receiver
529 * thread be the one who is waiting for the signal.
531 * Returns 0 if successful; otherwise it returns an error code:
532 * EINVAL: the signal specified by signal is not
533 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
535 * EAGAIN: no resources are available to queue the signal; the
536 * maximum number of queued signals has been reached, or a
537 * systemwide resource limit has been exceeded
539 * Alternatively, in case of error the implementation is allowed to
540 * notify it to the system console and then terminate the FRSH
541 * implementation and dependant applications
543 int fosa_signal_queue
544 (frsh_signal_t signal, frsh_signal_info_t info,
545 frsh_thread_id_t receiver)
547 // note: in MaRTE OS the signal is sent to any interested thread
548 pid_t pid=1; // dummy value; the pid is ignored in MaRTE OS
550 err=sigqueue(pid,signal,*((union sigval *)(&info)));
551 // the above casting construct is used to overcome the compiler
552 // restriction that does not allow casts between unions
566 * The function waits for the arrival of one of the signals in the
567 * array of signal numbers specified by set, which must be of size
568 * equal to size. If there is a signal already queued, the function
569 * returns immediately. If there is no signal of the specified set
570 * queued, the calling thread is suspended until a signal from that
571 * set arrives. Upon return, if signal_received is not NULL the number
572 * of the signal received is stored in the variable pointed to by
573 * signal_received; and if info is not NULL the associated information
574 * is stored in the variable pointed to by info.
576 * Returns 0 if successful; otherwise it returns an error code:
577 * EINVAL: the array contains one or more values which are not
578 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
581 * Alternatively, in case of error the implementation is allowed to
582 * notify it to the system console and then terminate the FRSH
583 * implementation and dependant applications
586 (frsh_signal_t set[], int size, frsh_signal_t *signal_received,
587 frsh_signal_info_t *info)
593 CHKE(sigemptyset(&signalset));
594 for(i=0;i<size;i++) {
595 CHKE(sigaddset(&signalset,set[i]));
598 err=sigwaitinfo(&signalset,&siginfo);
600 *signal_received=siginfo.si_signo;
601 *info=*((frsh_signal_info_t *)(&siginfo.si_value));
609 * fosa_signal_timedwait()
611 * Timed wait for a signal
613 * This function behaves the same as fosa_signal_wait(), except that
614 * the suspension time is limited to the time interval specified in
615 * the timespec structure referenced by timeout.
617 * Returns 0 if successful; otherwise it returns an error code:
618 * EINVAL: the array contains one or more values which are not
619 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
620 * is less than 0, or timeout is invalid
621 * EAGAIN: The timeout expired
623 * Alternatively, in case of the EINVAL error the implementation is
624 * allowed to notify it to the system console and then terminate the
625 * FRSH implementation and dependant applications
627 int fosa_signal_timedwait
628 (frsh_signal_t set[], int size, frsh_signal_t *signal_received,
629 frsh_signal_info_t *info, const struct timespec *timeout)
632 // the implementation of sigtimedwait is not yet available in MaRTE OS
636 /* sigset_t signalset; */
637 /* siginfo_t siginfo; */
639 /* CHKE(sigemptyset(&signalset)); */
640 /* for(i=0;i<size;i++) { */
641 /* CHKE(sigaddset(&signalset,set[i])); */
644 /* err=sigtimedwait(&signalset,&siginfo,timeout); */
646 /* *signal_received=siginfo.si_signo; */
647 /* *info=siginfo.si_value; */