1 // -----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2008 FRESCOR consortium partners:
4 // Universidad de Cantabria, SPAIN
5 // University of York, UK
6 // Scuola Superiore Sant'Anna, ITALY
7 // Kaiserslautern University, GERMANY
8 // Univ. Politécnica 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 for a link to partners' websites
18 // 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 // FSF API web pages: http://marte.unican.es/fsf/docs
32 // http://shark.sssup.it/contrib/first/docs/
34 // This file is part of FOSA (Frsh Operating System Adaption)
36 // FOSA is free software; you can redistribute it and/or modify it
37 // under terms of the GNU General Public License as published by the
38 // Free Software Foundation; either version 2, or (at your option) any
39 // later version. FOSA is distributed in the hope that it will be
40 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
41 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42 // General Public License for more details. You should have received a
43 // copy of the GNU General Public License along with FOSA; see file
44 // COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
45 // Cambridge, MA 02139, USA.
47 // As a special exception, including FOSA header files in a file,
48 // instantiating FOSA generics or templates, or linking other files
49 // with FOSA objects to produce an executable application, does not
50 // by itself cause the resulting executable application to be covered
51 // by the GNU General Public License. This exception does not
52 // however invalidate any other reasons why the executable file might be
53 // covered by the GNU Public License.
54 // -----------------------------------------------------------------------
55 //fosa_threads_and_signals.c
56 //==============================================
57 // ******** ****** ******** **********
58 // **///// /** ** **////// /** /**
59 // ** /** ** /** /** /**
60 // ******* /** ** /********* /**********
61 // **//// /** ** ////////** /**//////**
62 // ** /** ** /** /** /**
63 // ** /** ** ******** /** /**
64 // // /******/ //////// // //
66 // FOSA(Frescor Operating System Adaptation layer)
67 //================================================
69 #include "fosa_threads_and_signals.h"
70 #include "fosa_configuration_parameters.h"
76 #include <misc/error_checks.h>
79 * @defgroup threadandsignals Thread and Signals
82 * This module defines the functions that manipulate frsh_threads and
83 * frsh_signals inside FRSH implementation.
85 * Applications can refer to FRSH threads but they cannot create them
86 * directly, instead they must use frsh_thread_create*() which in turn
87 * use fosa_thread_create().
89 * For signals, we assume that the OS provides a direct mapping
90 * for frsh_signal_t and frsh_signal_info_t in the native interface.
95 //////////////////////////////////////////////////////////////////
96 // Storage of thread-specific keys
97 // - key_list is an array containing the keys
98 // - key_in_use is an array of booleans
99 // - key_lock is a mutex that locks the data structure
100 // while creating a new key
101 // - keys_initialized indicates whether the key_in_use array and
102 // the key_lock mutex are initialized or not; it is declared
103 // volatile as it may be accessed concurrently
104 //////////////////////////////////////////////////////////////////
106 static pthread_key_t key_list[FOSA_MAX_KEYS];
107 static bool key_in_use[FOSA_MAX_KEYS];
108 static pthread_once_t keys_initialized=PTHREAD_ONCE_INIT;
109 static pthread_mutex_t key_lock;
112 // Initialize the keys data structure
113 // This function should be called from pthread_once() to ensure
114 // one single initialization
117 pthread_mutexattr_t attr;
120 // initialize the key_in_use array and the mutex
121 for(i=0; i<FOSA_MAX_KEYS;i++) {
124 // Initialize the mutex
125 CHK(pthread_mutexattr_init(&attr));
126 // we use the priority inheritance protocol because we don't know which
127 // tasks will be using the mutex
128 CHK(pthread_mutexattr_setprotocol(&attr,PTHREAD_PRIO_INHERIT));
129 CHK(pthread_mutex_init(&key_lock,&attr));
130 CHK(pthread_mutexattr_destroy(&attr));
133 /*************************
134 * Thread identification
135 *************************/
138 * fosa_thread_equal()
140 * Compare two thread identifiers to determine if they refer to the
143 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
145 return pthread_equal(t1,t2);
152 * Return the thread id of the calling thread
154 fosa_thread_id_t fosa_thread_self()
156 return pthread_self();
159 /*************************
161 *************************/
164 * fosa_thread_attr_init()
166 * Initialize a thread attributes object
168 * This function initializes the object pointed to by attr to all
169 * the default values defined by FRSH
171 * @return 0 if successful; otherwise it returns \n
172 * FOSA_ENOMEM: insufficient memory exists to initialize the thread
175 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
179 ret_value=pthread_attr_init(attr);
181 // set the default values
183 // detachstate = detached thread (no join operation allowed)
184 CHK(pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED));
186 // inheritsched = explicit, so that we can explicitly set the attributes
187 CHK(pthread_attr_setinheritsched(attr,PTHREAD_EXPLICIT_SCHED));
189 // schedpolicy = fixed priorities
190 CHK(pthread_attr_setschedpolicy(attr,SCHED_FIFO));
192 // detachstate = detached thread (no join operation allowed)
193 CHK(pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED));
200 * fosa_thread_attr_destroy()
202 * Destroy a thread attributes object
204 * This function is used to destroy the thread attributes object,
205 * pointed to by attr, and deallocate any system resources allocated for it
209 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
211 return pthread_attr_destroy(attr);
215 * fosa_thread_attr_set_stacksize()
217 * Set the thread minimum stack size in a thread attributes object
219 * This function sets the minimum stack size of the thread attributes
220 * object attr to the value given by stacksize, in bytes. This
221 * function has no runtime effect on the stack size, except when the
222 * attributes object is used to create a thread, when it will be
223 * created with the specified minimum stack size
225 * @return 0 if successful, or the following error code:
226 * FOSA_EINVAL: the specified stacksize value is not supported in
227 * this implementation
229 int fosa_thread_attr_set_stacksize
230 (fosa_thread_attr_t *attr, size_t stacksize)
232 return pthread_attr_setstacksize(attr,stacksize);
236 * fosa_thread_attr_get_stacksize()
238 * Get the thread minimum stack size from a thread attributes object
240 * This function sets the variable pointed to by stacksize to the
241 * minimum stack size stored in the thread attributes object attr.
245 int fosa_thread_attr_get_stacksize
246 (const fosa_thread_attr_t *attr, size_t *stacksize)
248 return pthread_attr_getstacksize(attr,stacksize);
252 /*************************
253 * Thread creation and termination
254 *************************/
257 * fosa_thread_create()
259 * This function creates a new thread using the attributes specified
260 * in attr. If attr is NULL, default attributes are used. The new
261 * thread starts running immediately, executing the function specified
262 * by code, with an argument equal to arg. Upon successful return, the
263 * variable pointed to by tid will contain the identifier of the newly
264 * created thread. The set of signals that may be synchronously
265 * accepted is inherited from the parent thread.
267 * Returns 0 if successful; otherwise it returs a code error:
269 * EAGAIN: the system lacks the necessary resources to create a
270 * new thread or the maximum number of threads has been
273 * EINVAL: the value specified by attr is invalid (for instance,
274 * it has not been correctly initialized)
276 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
277 * possibly because of incorrect attributes, or because the
278 * requested minimum capacity cannot be guaranteed
281 int fosa_thread_create
282 (fosa_thread_id_t *tid, const fosa_thread_attr_t *attr,
283 fosa_thread_code_t code, void * arg)
285 return pthread_create(tid,attr,code,arg);
290 * Note: no thread termination primitive is provided. The termination
291 * of a thread will be notified by the system to the FRSH scheduler
292 * through the scheduler API
296 /**************************************************
297 * Thread-specific data
298 * (extended with access from a different thread)
300 * Several data items (pointers) may be associated with each thread
301 * Each item is identified through a key, an integer value between 0
302 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
303 * deallocating the memory area pointed to by the pointer
304 **************************************************/
309 * Create a new key for thread specific data.
311 * Prior to setting data in a key, we need ask the system to create
314 * @return 0 if successful \n
315 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
316 * FOSA_ENOMEM If there are no enough memory resources to
319 int fosa_key_create(int *key)
325 // initialize the keys data structure if needed
326 CHK(pthread_once(&keys_initialized, init_keys));
329 CHK(pthread_mutex_lock(&key_lock));
331 // find an unused key
332 for(i=0; i<FOSA_MAX_KEYS;i++) {
333 if (!key_in_use[i]) {
336 ret_value=pthread_key_create(&(key_list[i]),NULL);
341 // unlock the mutex before returning
342 CHK(pthread_mutex_unlock(&key_lock));
344 // all keys are in use; max keys reached
345 ret_value=FOSA_EINVAL;
355 * This destroys the key and isables its use in the system
357 * @return 0 if successful \n
358 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
360 int fosa_key_destroy(int key)
365 CHK(pthread_mutex_lock(&key_lock));
367 // destroy the key and mark it as available
368 ret_value=pthread_key_delete(key_list[key]);
370 key_in_use[key]=false;
373 // unlock the mutex before returning
374 CHK(pthread_mutex_unlock(&key_lock));
380 * fosa_thread_set_specific_data()
382 * Set thread-specific data
384 * For the thread identified by tid, the thread-specifid data field
385 * identified by key will be set to the value specified by value
387 * Returns 0 if successful; otherwise, an error code is returned
388 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
390 * Alternatively, in case of error the implementation is allowed to
391 * notify it to the system console and then terminate the FRSH
392 * implementation and dependant applications
394 int fosa_thread_set_specific_data
395 (int key, fosa_thread_id_t tid, const void * value)
397 return pthread_setspecific_for(key_list[key],tid,value);
401 * fosa_thread_get_specific_data()
403 * Get thread-specific data
405 * For the thread identified by tid, the thread-specifid data field
406 * identified by key will be copied to the variable pointed to by value
408 * Returns 0 if successful; otherwise, an error code is returned
409 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
411 * Alternatively, in case of error the implementation is allowed to
412 * notify it to the system console and then terminate the FRSH
413 * implementation and dependant applications
415 int fosa_thread_get_specific_data(int key, fosa_thread_id_t tid,
418 return pthread_getspecific_from(key_list[key],tid,value);
422 /******************************************************************
425 * This implementation of FRSH assumes an underlying fixed priority
426 * scheduler with priorities in a range, with a minimum and a
427 * maximumm, a number of priority levels with at least 31
428 * priorities. A larger number implies a larger priority. In systems
429 * in which the underlying scheduler uses the opposite convention, a
430 * mapping is automatically provided by the OS adaptation layer.
431 *******************************************************************/
434 * fosa_get_priority_max()
436 * Return the maximum priority value used in this implementation
438 int fosa_get_priority_max()
440 return sched_get_priority_max(SCHED_APP);
444 * fosa_get_priority_min()
446 * Return the minimum priority value used in this implementation
448 int fosa_get_priority_min()
450 return sched_get_priority_min(SCHED_APP);
454 * fosa_thread_attr_set_prio()
456 * Change the priority of a thread attributes object
458 * The priority of the thread attriutes object specified by attr is
459 * set to the value specified by prio. This function has no runtime
460 * effect on the priority, except when the attributes object is used
461 * to create a thread, when it will be created with the specified
464 * Returns 0 if successful, or the following error code:
465 * EINVAL: the specified priority value is not between the
466 * minimum and the maximum priorities defined in this
467 * FRSH implementation
468 * Alternatively, in case of error the implementation is allowed to
469 * notify it to the system console and then terminate the FRSH
470 * implementation and dependant applications
472 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
474 struct sched_param param;
476 param.sched_priority=prio;
477 return pthread_attr_setschedparam(attr,¶m);
481 * fosa_thread_attr_get_prio()
483 * Get the priority from a thread attributes object
485 * This function sets the variable pointed to by prio to the
486 * priority stored in the thread attributes object attr.
490 int fosa_thread_attr_get_prio
491 (const fosa_thread_attr_t *attr, int *prio)
493 struct sched_param param;
496 ret_value=pthread_attr_getschedparam(attr,¶m);
498 *prio=param.sched_priority;
504 * fosa_thread_set_prio()
506 * Dynamically change the priority of a thread
508 * The priority of the thread identified by tid is
509 * set to the value specified by prio.
511 * Returns 0 if successful, or the following error code:
512 * EINVAL: the specified priority value is not between the
513 * minimum and the maximum priorities defined in this
514 * FRSH implementation
515 * Alternatively, in case of error the implementation is allowed to
516 * notify it to the system console and then terminate the FRSH
517 * implementation and dependant applications
519 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
521 struct sched_param param;
522 int policy, ret_value;
524 ret_value=pthread_getschedparam(tid,&policy,¶m);
525 if (ret_value!=0) return ret_value;
527 param.sched_priority=prio;
528 return pthread_setschedparam(tid,policy,¶m);
532 * fosa_thread_get_prio()
534 * Dynamically get the priority of a thread
536 * This function sets the variable pointed to by prio to the
537 * priority of the thread identified by tid
541 int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio)
543 struct sched_param param;
544 int policy, ret_value;
546 ret_value=pthread_getschedparam(tid,&policy,¶m);
548 *prio=param.sched_priority;
555 /*******************************************************************
558 * Signals represent events that may be notified by the system, or
559 * sent explicitly by the application, and for which a thread may
560 * synchronously wait. Signals carry an associated piece of
561 * information (an integer or a pointer) and are queued until they are
562 * accepted. Signals are identified by an integer signal number (of
563 * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
564 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
566 *******************************************************************/
569 * fosa_set_accepted_signals()
571 * Establish the set of signals that may be synchronously accepted
572 * by the calling thread
574 * The function uses the array of signal numbers specified by set,
575 * which must be of size equal to size
577 * Returns 0 if successful; otherwise it returns an error code:
578 * EINVAL: the array contains one or more values which are not
579 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
582 * Alternatively, in case of error the implementation is allowed to
583 * notify it to the system console and then terminate the FRSH
584 * implementation and dependant applications
586 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
590 struct sigaction act;
592 // empty the signal set
593 CHKE(sigemptyset(&signalset));
595 // configure the signal action to make the signal a real-time
596 // signal that can be queued
597 act.sa_handler=SIG_DFL;
598 act.sa_mask=signalset;
599 act.sa_flags=SA_SIGINFO;
600 act.sa_sigaction=NULL;
602 // loop for all signals in set
603 for(i=0;i<size;i++) {
604 CHKE(sigaddset(&signalset,set[i]));
605 // Configure the signal so that it can be queued with data
606 CHKE(sigaction(set[i],&act,NULL));
608 return pthread_sigmask(SIG_BLOCK,&signalset,NULL);
612 * fosa_signal_queue()
616 * This function is used to explicitly send a signal with a specified
619 * The signal number specified by signal is sent together with the
620 * information specified by info, to the thread identified by
621 * receiver. In those implementations that do not support queueing a
622 * signal with information to a thread (such as POSIX), the signal may
623 * be sent to any thread that is waiting for this signal via
624 * fosa_signal_wait(). Portability can be ensured by having the receiver
625 * thread be the one who is waiting for the signal.
627 * Returns 0 if successful; otherwise it returns an error code:
628 * EINVAL: the signal specified by signal is not
629 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
631 * EAGAIN: no resources are available to queue the signal; the
632 * maximum number of queued signals has been reached, or a
633 * systemwide resource limit has been exceeded
635 * Alternatively, in case of error the implementation is allowed to
636 * notify it to the system console and then terminate the FRSH
637 * implementation and dependant applications
639 int fosa_signal_queue
640 (fosa_signal_t signal, fosa_signal_info_t info,
641 fosa_thread_id_t receiver)
643 // note: in MaRTE OS the signal is sent to any interested thread
644 pid_t pid=1; // dummy value; the pid is ignored in MaRTE OS
646 err=sigqueue(pid,signal,*((union sigval *)(&info)));
647 // the above casting construct is used to overcome the compiler
648 // restriction that does not allow casts between unions
662 * The function waits for the arrival of one of the signals in the
663 * array of signal numbers specified by set, which must be of size
664 * equal to size. If there is a signal already queued, the function
665 * returns immediately. If there is no signal of the specified set
666 * queued, the calling thread is suspended until a signal from that
667 * set arrives. Upon return, if signal_received is not NULL the number
668 * of the signal received is stored in the variable pointed to by
669 * signal_received; and if info is not NULL the associated information
670 * is stored in the variable pointed to by info.
672 * Returns 0 if successful; otherwise it returns an error code:
673 * EINVAL: the array contains one or more values which are not
674 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
677 * Alternatively, in case of error the implementation is allowed to
678 * notify it to the system console and then terminate the FRSH
679 * implementation and dependant applications
682 (fosa_signal_t set[], int size, fosa_signal_t *signal_received,
683 fosa_signal_info_t *info)
689 CHKE(sigemptyset(&signalset));
690 for(i=0;i<size;i++) {
691 CHKE(sigaddset(&signalset,set[i]));
694 err=sigwaitinfo(&signalset,&siginfo);
696 *signal_received=siginfo.si_signo;
697 *info=*((fosa_signal_info_t *)(&siginfo.si_value));
705 * fosa_signal_timedwait()
707 * Timed wait for a signal
709 * This function behaves the same as fosa_signal_wait(), except that
710 * the suspension time is limited to the time interval specified in
711 * the timespec structure referenced by timeout.
713 * Returns 0 if successful; otherwise it returns an error code:
714 * EINVAL: the array contains one or more values which are not
715 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
716 * is less than 0, or timeout is invalid
717 * EAGAIN: The timeout expired
719 * Alternatively, in case of the EINVAL error the implementation is
720 * allowed to notify it to the system console and then terminate the
721 * FRSH implementation and dependant applications
723 int fosa_signal_timedwait
724 (fosa_signal_t set[], int size, fosa_signal_t *signal_received,
725 fosa_signal_info_t *info, const fosa_rel_time_t *timeout)
728 // the implementation of sigtimedwait is not yet available in MaRTE OS
732 /* sigset_t signalset; */
733 /* siginfo_t siginfo; */
735 /* CHKE(sigemptyset(&signalset)); */
736 /* for(i=0;i<size;i++) { */
737 /* CHKE(sigaddset(&signalset,set[i])); */
740 /* err=sigtimedwait(&signalset,&siginfo,timeout); */
742 /* *signal_received=siginfo.si_signo; */
743 /* *info=siginfo.si_value; */