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(fosa_thread_id_t t1, fosa_thread_id_t t2)
142 return pthread_equal(t1,t2);
149 * Return the thread id of the calling thread
151 fosa_thread_id_t fosa_thread_self()
153 return pthread_self();
156 /*************************
158 *************************/
161 * fosa_thread_attr_init()
163 * Initialize a thread attributes object
165 * This function initializes the object pointed to by attr to all
166 * the default values defined by FRSH
168 * @return 0 if successful; otherwise it returns \n
169 * FOSA_ENOMEM: insufficient memory exists to initialize the thread
172 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
176 ret_value=pthread_attr_init(attr);
178 // set the default values
180 // detachstate = detached thread (no join operation allowed)
181 CHK(pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED));
183 // inheritsched = explicit, so that we can explicitly set the attributes
184 CHK(pthread_attr_setinheritsched(attr,PTHREAD_EXPLICIT_SCHED));
186 // schedpolicy = fixed priorities
187 CHK(pthread_attr_setschedpolicy(attr,SCHED_FIFO));
189 // detachstate = detached thread (no join operation allowed)
190 CHK(pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED));
197 * fosa_thread_attr_destroy()
199 * Destroy a thread attributes object
201 * This function is used to destroy the thread attributes object,
202 * pointed to by attr, and deallocate any system resources allocated for it
206 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
208 return pthread_attr_destroy(attr);
212 * fosa_thread_attr_set_stacksize()
214 * Set the thread minimum stack size in a thread attributes object
216 * This function sets the minimum stack size of the thread attributes
217 * object attr to the value given by stacksize, in bytes. This
218 * function has no runtime effect on the stack size, except when the
219 * attributes object is used to create a thread, when it will be
220 * created with the specified minimum stack size
222 * @return 0 if successful, or the following error code:
223 * FOSA_EINVAL: the specified stacksize value is not supported in
224 * this implementation
226 int fosa_thread_attr_set_stacksize
227 (fosa_thread_attr_t *attr, size_t stacksize)
229 return pthread_attr_setstacksize(attr,stacksize);
233 * fosa_thread_attr_get_stacksize()
235 * Get the thread minimum stack size from a thread attributes object
237 * This function sets the variable pointed to by stacksize to the
238 * minimum stack size stored in the thread attributes object attr.
242 int fosa_thread_attr_get_stacksize
243 (const fosa_thread_attr_t *attr, size_t *stacksize)
245 return pthread_attr_getstacksize(attr,stacksize);
249 /*************************
250 * Thread creation and termination
251 *************************/
254 * fosa_thread_create()
256 * This function creates a new thread using the attributes specified
257 * in attr. If attr is NULL, default attributes are used. The new
258 * thread starts running immediately, executing the function specified
259 * by code, with an argument equal to arg. Upon successful return, the
260 * variable pointed to by tid will contain the identifier of the newly
261 * created thread. The set of signals that may be synchronously
262 * accepted is inherited from the parent thread.
264 * Returns 0 if successful; otherwise it returs a code error:
266 * EAGAIN: the system lacks the necessary resources to create a
267 * new thread or the maximum number of threads has been
270 * EINVAL: the value specified by attr is invalid (for instance,
271 * it has not been correctly initialized)
273 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
274 * possibly because of incorrect attributes, or because the
275 * requested minimum capacity cannot be guaranteed
278 int fosa_thread_create
279 (fosa_thread_id_t *tid, const fosa_thread_attr_t *attr,
280 fosa_thread_code_t code, void * arg)
282 return pthread_create(tid,attr,code,arg);
287 * Note: no thread termination primitive is provided. The termination
288 * of a thread will be notified by the system to the FRSH scheduler
289 * through the scheduler API
293 /**************************************************
294 * Thread-specific data
295 * (extended with access from a different thread)
297 * Several data items (pointers) may be associated with each thread
298 * Each item is identified through a key, an integer value between 0
299 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
300 * deallocating the memory area pointed to by the pointer
301 **************************************************/
306 * Create a new key for thread specific data.
308 * Prior to setting data in a key, we need ask the system to create
311 * @return 0 if successful \n
312 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
313 * FOSA_ENOMEM If there are no enough memory resources to
316 int fosa_key_create(int *key)
322 // initialize the keys data structure if needed
323 CHK(pthread_once(&keys_initialized, init_keys));
326 CHK(pthread_mutex_lock(&key_lock));
328 // find an unused key
329 for(i=0; i<FOSA_MAX_KEYS;i++) {
330 if (!key_in_use[i]) {
333 ret_value=pthread_key_create(&(key_list[i]),NULL);
338 // unlock the mutex before returning
339 CHK(pthread_mutex_unlock(&key_lock));
341 // all keys are in use; max keys reached
342 ret_value=FOSA_EINVAL;
352 * This destroys the key and isables its use in the system
354 * @return 0 if successful \n
355 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
357 int fosa_key_destroy(int key)
362 CHK(pthread_mutex_lock(&key_lock));
364 // destroy the key and mark it as available
365 ret_value=pthread_key_delete(key_list[key]);
367 key_in_use[key]=false;
370 // unlock the mutex before returning
371 CHK(pthread_mutex_unlock(&key_lock));
377 * fosa_thread_set_specific_data()
379 * Set thread-specific data
381 * For the thread identified by tid, the thread-specifid data field
382 * identified by key will be set to the value specified by value
384 * Returns 0 if successful; otherwise, an error code is returned
385 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
387 * Alternatively, in case of error the implementation is allowed to
388 * notify it to the system console and then terminate the FRSH
389 * implementation and dependant applications
391 int fosa_thread_set_specific_data
392 (int key, fosa_thread_id_t tid, const void * value)
394 return pthread_setspecific_for(key_list[key],tid,value);
398 * fosa_thread_get_specific_data()
400 * Get thread-specific data
402 * For the thread identified by tid, the thread-specifid data field
403 * identified by key will be copied to the variable pointed to by value
405 * Returns 0 if successful; otherwise, an error code is returned
406 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
408 * Alternatively, in case of error the implementation is allowed to
409 * notify it to the system console and then terminate the FRSH
410 * implementation and dependant applications
412 int fosa_thread_get_specific_data(int key, fosa_thread_id_t tid,
415 return pthread_getspecific_from(key_list[key],tid,value);
419 /******************************************************************
422 * This implementation of FRSH assumes an underlying fixed priority
423 * scheduler with priorities in a range, with a minimum and a
424 * maximumm, a number of priority levels with at least 31
425 * priorities. A larger number implies a larger priority. In systems
426 * in which the underlying scheduler uses the opposite convention, a
427 * mapping is automatically provided by the OS adaptation layer.
428 *******************************************************************/
431 * fosa_get_priority_max()
433 * Return the maximum priority value used in this implementation
435 int fosa_get_priority_max()
437 return sched_get_priority_max(SCHED_APP);
441 * fosa_get_priority_min()
443 * Return the minimum priority value used in this implementation
445 int fosa_get_priority_min()
447 return sched_get_priority_min(SCHED_APP);
451 * fosa_thread_attr_set_prio()
453 * Change the priority of a thread attributes object
455 * The priority of the thread attriutes object specified by attr is
456 * set to the value specified by prio. This function has no runtime
457 * effect on the priority, except when the attributes object is used
458 * to create a thread, when it will be created with the specified
461 * Returns 0 if successful, or the following error code:
462 * EINVAL: the specified priority value is not between the
463 * minimum and the maximum priorities defined in this
464 * FRSH implementation
465 * Alternatively, in case of error the implementation is allowed to
466 * notify it to the system console and then terminate the FRSH
467 * implementation and dependant applications
469 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
471 struct sched_param param;
473 param.sched_priority=prio;
474 return pthread_attr_setschedparam(attr,¶m);
478 * fosa_thread_attr_get_prio()
480 * Get the priority from a thread attributes object
482 * This function sets the variable pointed to by prio to the
483 * priority stored in the thread attributes object attr.
487 int fosa_thread_attr_get_prio
488 (const fosa_thread_attr_t *attr, int *prio)
490 struct sched_param param;
493 ret_value=pthread_attr_getschedparam(attr,¶m);
495 *prio=param.sched_priority;
501 * fosa_thread_set_prio()
503 * Dynamically change the priority of a thread
505 * The priority of the thread identified by tid is
506 * set to the value specified by prio.
508 * Returns 0 if successful, or the following error code:
509 * EINVAL: the specified priority value is not between the
510 * minimum and the maximum priorities defined in this
511 * FRSH implementation
512 * Alternatively, in case of error the implementation is allowed to
513 * notify it to the system console and then terminate the FRSH
514 * implementation and dependant applications
516 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
518 struct sched_param param;
519 int policy, ret_value;
521 ret_value=pthread_getschedparam(tid,&policy,¶m);
522 if (ret_value!=0) return ret_value;
524 param.sched_priority=prio;
525 return pthread_setschedparam(tid,policy,¶m);
529 * fosa_thread_get_prio()
531 * Dynamically get the priority of a thread
533 * This function sets the variable pointed to by prio to the
534 * priority of the thread identified by tid
538 int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio)
540 struct sched_param param;
541 int policy, ret_value;
543 ret_value=pthread_getschedparam(tid,&policy,¶m);
545 *prio=param.sched_priority;
552 /*******************************************************************
555 * Signals represent events that may be notified by the system, or
556 * sent explicitly by the application, and for which a thread may
557 * synchronously wait. Signals carry an associated piece of
558 * information (an integer or a pointer) and are queued until they are
559 * accepted. Signals are identified by an integer signal number (of
560 * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
561 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
563 *******************************************************************/
566 * fosa_set_accepted_signals()
568 * Establish the set of signals that may be synchronously accepted
569 * by the calling thread
571 * The function uses the array of signal numbers specified by set,
572 * which must be of size equal to size
574 * Returns 0 if successful; otherwise it returns an error code:
575 * EINVAL: the array contains one or more values which are not
576 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
579 * Alternatively, in case of error the implementation is allowed to
580 * notify it to the system console and then terminate the FRSH
581 * implementation and dependant applications
583 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
587 struct sigaction act;
589 // empty the signal set
590 CHKE(sigemptyset(&signalset));
592 // configure the signal action to make the signal a real-time
593 // signal that can be queued
594 act.sa_handler=SIG_DFL;
595 act.sa_mask=signalset;
596 act.sa_flags=SA_SIGINFO;
597 act.sa_sigaction=NULL;
599 // loop for all signals in set
600 for(i=0;i<size;i++) {
601 CHKE(sigaddset(&signalset,set[i]));
602 // Configure the signal so that it can be queued with data
603 CHKE(sigaction(set[i],&act,NULL));
605 return pthread_sigmask(SIG_BLOCK,&signalset,NULL);
609 * fosa_signal_queue()
613 * This function is used to explicitly send a signal with a specified
616 * The signal number specified by signal is sent together with the
617 * information specified by info, to the thread identified by
618 * receiver. In those implementations that do not support queueing a
619 * signal with information to a thread (such as POSIX), the signal may
620 * be sent to any thread that is waiting for this signal via
621 * fosa_signal_wait(). Portability can be ensured by having the receiver
622 * thread be the one who is waiting for the signal.
624 * Returns 0 if successful; otherwise it returns an error code:
625 * EINVAL: the signal specified by signal is not
626 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
628 * EAGAIN: no resources are available to queue the signal; the
629 * maximum number of queued signals has been reached, or a
630 * systemwide resource limit has been exceeded
632 * Alternatively, in case of error the implementation is allowed to
633 * notify it to the system console and then terminate the FRSH
634 * implementation and dependant applications
636 int fosa_signal_queue
637 (fosa_signal_t signal, fosa_signal_info_t info,
638 fosa_thread_id_t receiver)
640 // note: in MaRTE OS the signal is sent to any interested thread
641 pid_t pid=1; // dummy value; the pid is ignored in MaRTE OS
643 err=sigqueue(pid,signal,*((union sigval *)(&info)));
644 // the above casting construct is used to overcome the compiler
645 // restriction that does not allow casts between unions
659 * The function waits for the arrival of one of the signals in the
660 * array of signal numbers specified by set, which must be of size
661 * equal to size. If there is a signal already queued, the function
662 * returns immediately. If there is no signal of the specified set
663 * queued, the calling thread is suspended until a signal from that
664 * set arrives. Upon return, if signal_received is not NULL the number
665 * of the signal received is stored in the variable pointed to by
666 * signal_received; and if info is not NULL the associated information
667 * is stored in the variable pointed to by info.
669 * Returns 0 if successful; otherwise it returns an error code:
670 * EINVAL: the array contains one or more values which are not
671 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
674 * Alternatively, in case of error the implementation is allowed to
675 * notify it to the system console and then terminate the FRSH
676 * implementation and dependant applications
679 (fosa_signal_t set[], int size, fosa_signal_t *signal_received,
680 fosa_signal_info_t *info)
686 CHKE(sigemptyset(&signalset));
687 for(i=0;i<size;i++) {
688 CHKE(sigaddset(&signalset,set[i]));
691 err=sigwaitinfo(&signalset,&siginfo);
693 *signal_received=siginfo.si_signo;
694 *info=*((fosa_signal_info_t *)(&siginfo.si_value));
702 * fosa_signal_timedwait()
704 * Timed wait for a signal
706 * This function behaves the same as fosa_signal_wait(), except that
707 * the suspension time is limited to the time interval specified in
708 * the timespec structure referenced by timeout.
710 * Returns 0 if successful; otherwise it returns an error code:
711 * EINVAL: the array contains one or more values which are not
712 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
713 * is less than 0, or timeout is invalid
714 * EAGAIN: The timeout expired
716 * Alternatively, in case of the EINVAL error the implementation is
717 * allowed to notify it to the system console and then terminate the
718 * FRSH implementation and dependant applications
720 int fosa_signal_timedwait
721 (fosa_signal_t set[], int size, fosa_signal_t *signal_received,
722 fosa_signal_info_t *info, const struct timespec *timeout)
725 // the implementation of sigtimedwait is not yet available in MaRTE OS
729 /* sigset_t signalset; */
730 /* siginfo_t siginfo; */
732 /* CHKE(sigemptyset(&signalset)); */
733 /* for(i=0;i<size;i++) { */
734 /* CHKE(sigaddset(&signalset,set[i])); */
737 /* err=sigtimedwait(&signalset,&siginfo,timeout); */
739 /* *signal_received=siginfo.si_signo; */
740 /* *info=siginfo.si_value; */