1 // -----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2007 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. 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 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
23 // This file is part of the FRSH implementation
25 // FRSH is free software; you can redistribute it and/or modify
26 // it under the terms of the GNU General Public License as published by
27 // the Free Software Foundation; either version 2, or (at your option)
30 // FRSH is distributed in the hope that it will be useful, but
31 // WITHOUT ANY WARRANTY; without even the implied warranty of
32 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 // General Public License for more details.
35 // You should have received a copy of the GNU General Public License
36 // distributed with FRSH; see file COPYING. If not, write to the
37 // Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
40 // -----------------------------------------------------------------------
41 //fosa_threads_and_signals.c
42 //==============================================
43 // ******** ****** ******** **********
44 // **///// /** ** **////// /** /**
45 // ** /** ** /** /** /**
46 // ******* /** ** /********* /**********
47 // **//// /** ** ////////** /**//////**
48 // ** /** ** /** /** /**
49 // ** /** ** ******** /** /**
50 // // /******/ //////// // //
52 // FOSA(Frescor Operating System Adaptation layer)
53 //================================================
55 #include "fosa_threads_and_signals.h"
56 #include "fosa_configuration_parameters.h"
62 #include <misc/error_checks.h>
65 * @defgroup threadandsignals Thread and Signals
68 * This module defines the functions that manipulate frsh_threads and
69 * frsh_signals inside FRSH implementation.
71 * Applications can refer to FRSH threads but they cannot create them
72 * directly, instead they must use frsh_thread_create*() which in turn
73 * use fosa_thread_create().
75 * For signals, we assume that the OS provides a direct mapping
76 * for frsh_signal_t and frsh_signal_info_t in the native interface.
81 //////////////////////////////////////////////////////////////////
82 // Storage of thread-specific keys
83 // - key_list is an array containing the keys
84 // - key_in_use is an array of booleans
85 // - key_lock is a mutex that locks the data structure
86 // while creating a new key
87 // - keys_initialized indicates whether the key_in_use array and
88 // the key_lock mutex are initialized or not; it is declared
89 // volatile as it may be accessed concurrently
90 //////////////////////////////////////////////////////////////////
92 static pthread_key_t key_list[FOSA_MAX_KEYS];
93 static bool key_in_use[FOSA_MAX_KEYS];
94 static pthread_once_t keys_initialized=PTHREAD_ONCE_INIT;
95 static pthread_mutex_t key_lock;
98 // Initialize the keys data structure
99 // This function should be called from pthread_once() to ensure
100 // one single initialization
103 pthread_mutexattr_t attr;
106 // initialize the key_in_use array and the mutex
107 for(i=0; i<FOSA_MAX_KEYS;i++) {
110 // Initialize the mutex
111 CHK(pthread_mutexattr_init(&attr));
112 // we use the priority inheritance protocol because we don't know which
113 // tasks will be using the mutex
114 CHK(pthread_mutexattr_setprotocol(&attr,PTHREAD_PRIO_INHERIT));
115 CHK(pthread_mutex_init(&key_lock,&attr));
116 CHK(pthread_mutexattr_destroy(&attr));
119 /*************************
120 * Thread identification
121 *************************/
124 * fosa_thread_equal()
126 * Compare two thread identifiers to determine if they refer to the
129 bool fosa_thread_equal(frsh_thread_id_t t1, frsh_thread_id_t t2)
131 return pthread_equal(t1,t2);
138 * Return the thread id of the calling thread
140 frsh_thread_id_t fosa_thread_self()
142 return pthread_self();
146 /*************************
147 * Thread creation and termination
148 *************************/
151 * fosa_thread_create()
153 * This function creates a new thread using the attributes specified
154 * in attr. If attr is NULL, default attributes are used. The new
155 * thread starts running immediately, executing the function specified
156 * by code, with an argument equal to arg. Upon successful return, the
157 * variable pointed to by tid will contain the identifier of the newly
158 * created thread. The set of signals that may be synchronously
159 * accepted is inherited from the parent thread.
161 * Returns 0 if successful; otherwise it returs a code error:
163 * EAGAIN: the system lacks the necessary resources to create a
164 * new thread or the maximum number of threads has been
167 * EINVAL: the value specified by attr is invalid (for instance,
168 * it has not been correctly initialized)
170 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
171 * possibly because of incorrect attributes, or because the
172 * requested minimum capacity cannot be guaranteed
175 int fosa_thread_create
176 (frsh_thread_id_t *tid, const frsh_thread_attr_t *attr,
177 frsh_thread_code_t code, void * arg)
179 return pthread_create(tid,attr,code,arg);
184 * Note: no thread termination primitive is provided. The termination
185 * of a thread will be notified by the system to the FRSH scheduler
186 * through the scheduler API
190 /**************************************************
191 * Thread-specific data
192 * (extended with access from a different thread)
194 * Several data items (pointers) may be associated with each thread
195 * Each item is identified through a key, an integer value between 0
196 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
197 * deallocating the memory area pointed to by the pointer
198 **************************************************/
203 * Create a new key for thread specific data.
205 * Prior to setting data in a key, we need ask the system to create
208 * @return 0 if successful \n
209 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
210 * FOSA_ENOMEM If there are no enough memory resources to
213 int fosa_key_create(int *key)
218 // initialize the keys data structure if needed
219 CHK(pthread_once(&keys_initialized, init_keys));
222 CHK(pthread_mutex_lock(&key_lock));
224 // find an unused key
225 for(i=0; i<FOSA_MAX_KEYS;i++) {
226 if (!key_in_use[i]) {
229 ret_value=pthread_key_create(&(key_list[i]),NULL);
234 // unlock the mutex before returning
235 CHK(pthread_mutex_unlock(&key_lock));
237 // all keys are in use; max keys reached
238 ret_value=FOSA_EINVAL;
248 * This destroys the key and isables its use in the system
250 * @return 0 if successful \n
251 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
253 int fosa_key_destroy(int key)
258 CHK(pthread_mutex_lock(&key_lock));
260 // destroy the key and mark it as available
261 ret_value=pthread_key_delete(key_list[key]);
263 key_in_use[key]=false;
266 // unlock the mutex before returning
267 CHK(pthread_mutex_unlock(&key_lock));
273 * fosa_thread_set_specific_data()
275 * Set thread-specific data
277 * For the thread identified by tid, the thread-specifid data field
278 * identified by key will be set to the value specified by value
280 * Returns 0 if successful; otherwise, an error code is returned
281 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
283 * Alternatively, in case of error the implementation is allowed to
284 * notify it to the system console and then terminate the FRSH
285 * implementation and dependant applications
287 int fosa_thread_set_specific_data
288 (int key, frsh_thread_id_t tid, const void * value)
290 return pthread_setspecific_for(key_list[key],tid,value);
294 * fosa_thread_get_specific_data()
296 * Get thread-specific data
298 * For the thread identified by tid, the thread-specifid data field
299 * identified by key will be copied to the variable pointed to by value
301 * Returns 0 if successful; otherwise, an error code is returned
302 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
304 * Alternatively, in case of error the implementation is allowed to
305 * notify it to the system console and then terminate the FRSH
306 * implementation and dependant applications
308 int fosa_thread_get_specific_data(int key, frsh_thread_id_t tid,
311 return pthread_getspecific_from(key_list[key],tid,value);
315 /******************************************************************
318 * This implementation of FRSH assumes an underlying fixed priority
319 * scheduler with priorities in a range, with a minimum and a
320 * maximumm, a number of priority levels with at least 31
321 * priorities. A larger number implies a larger priority. In systems
322 * in which the underlying scheduler uses the opposite convention, a
323 * mapping is automatically provided by the OS adaptation layer.
324 *******************************************************************/
327 * fosa_get_priority_max()
329 * Return the maximum priority value used in this implementation
331 int fosa_get_priority_max()
333 return sched_get_priority_max(SCHED_APP);
337 * fosa_get_priority_min()
339 * Return the minimum priority value used in this implementation
341 int fosa_get_priority_min()
343 return sched_get_priority_min(SCHED_APP);
347 * fosa_thread_attr_set_prio()
349 * Change the priority of a thread attributes object
351 * The priority of the thread attriutes object specified by attr is
352 * set to the value specified by prio. This function has no runtime
353 * effect on the priority, except when the attributes object is used
354 * to create a thread, when it will be created with the specified
357 * Returns 0 if successful, or the following error code:
358 * EINVAL: the specified priority value is not between the
359 * minimum and the maximum priorities defined in this
360 * FRSH implementation
361 * Alternatively, in case of error the implementation is allowed to
362 * notify it to the system console and then terminate the FRSH
363 * implementation and dependant applications
365 int fosa_thread_attr_set_prio(frsh_thread_attr_t *attr, int prio)
367 struct sched_param param;
369 param.sched_priority=prio;
370 return pthread_attr_setschedparam(attr,¶m);
374 * fosa_thread_attr_get_prio()
376 * Get the priority from a thread attributes object
378 * This function sets the variable pointed to by prio to the
379 * priority stored in the thread attributes object attr.
383 int fosa_thread_attr_get_prio
384 (const frsh_thread_attr_t *attr, int *prio)
386 struct sched_param param;
389 ret_value=pthread_attr_getschedparam(attr,¶m);
391 *prio=param.sched_priority;
397 * fosa_thread_set_prio()
399 * Dynamically change the priority of a thread
401 * The priority of the thread identified by tid is
402 * set to the value specified by prio.
404 * Returns 0 if successful, or the following error code:
405 * EINVAL: the specified priority value is not between the
406 * minimum and the maximum priorities defined in this
407 * FRSH implementation
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_set_prio(frsh_thread_id_t tid, int prio)
414 struct sched_param param;
415 int policy, ret_value;
417 ret_value=pthread_getschedparam(tid,&policy,¶m);
418 if (ret_value!=0) return ret_value;
420 param.sched_priority=prio;
421 return pthread_setschedparam(tid,policy,¶m);
425 * fosa_thread_get_prio()
427 * Dynamically get the priority of a thread
429 * This function sets the variable pointed to by prio to the
430 * priority of the thread identified by tid
434 int fosa_thread_get_prio (frsh_thread_id_t tid, int *prio)
436 struct sched_param param;
437 int policy, ret_value;
439 ret_value=pthread_getschedparam(tid,&policy,¶m);
441 *prio=param.sched_priority;
448 /*******************************************************************
451 * Signals represent events that may be notified by the system, or
452 * sent explicitly by the application, and for which a thread may
453 * synchronously wait. Signals carry an associated piece of
454 * information (an integer or a pointer) and are queued until they are
455 * accepted. Signals are identified by an integer signal number (of
456 * the type frsh_signal_t) in the range FOSA_SIGNAL_MIN,
457 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
459 *******************************************************************/
462 * fosa_set_accepted_signals()
464 * Establish the set of signals that may be synchronously accepted
465 * by the calling thread
467 * The function uses the array of signal numbers specified by set,
468 * which must be of size equal to size
470 * Returns 0 if successful; otherwise it returns an error code:
471 * EINVAL: the array contains one or more values which are not
472 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
475 * Alternatively, in case of error the implementation is allowed to
476 * notify it to the system console and then terminate the FRSH
477 * implementation and dependant applications
479 int fosa_set_accepted_signals(frsh_signal_t set[], int size)
483 struct sigaction act;
485 // empty the signal set
486 CHKE(sigemptyset(&signalset));
488 // configure the signal action to make the signal a real-time
489 // signal that can be queued
490 act.sa_handler=SIG_DFL;
491 act.sa_mask=signalset;
492 act.sa_flags=SA_SIGINFO;
493 act.sa_sigaction=NULL;
495 // loop for all signals in set
496 for(i=0;i<size;i++) {
497 CHKE(sigaddset(&signalset,set[i]));
498 // Configure the signal so that it can be queued with data
499 CHKE(sigaction(set[i],&act,NULL));
501 return pthread_sigmask(SIG_BLOCK,&signalset,NULL);
505 * fosa_signal_queue()
509 * This function is used to explicitly send a signal with a specified
512 * The signal number specified by signal is sent together with the
513 * information specified by info, to the thread identified by
514 * receiver. In those implementations that do not support queueing a
515 * signal with information to a thread (such as POSIX), the signal may
516 * be sent to any thread that is waiting for this signal via
517 * fosa_signal_wait(). Portability can be ensured by having the receiver
518 * thread be the one who is waiting for the signal.
520 * Returns 0 if successful; otherwise it returns an error code:
521 * EINVAL: the signal specified by signal is not
522 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
524 * EAGAIN: no resources are available to queue the signal; the
525 * maximum number of queued signals has been reached, or a
526 * systemwide resource limit has been exceeded
528 * Alternatively, in case of error the implementation is allowed to
529 * notify it to the system console and then terminate the FRSH
530 * implementation and dependant applications
532 int fosa_signal_queue
533 (frsh_signal_t signal, frsh_signal_info_t info,
534 frsh_thread_id_t receiver)
536 // note: in MaRTE OS the signal is sent to any interested thread
537 pid_t pid=1; // dummy value; the pid is ignored in MaRTE OS
539 err=sigqueue(pid,signal,*((union sigval *)(&info)));
540 // the above casting construct is used to overcome the compiler
541 // restriction that does not allow casts between unions
555 * The function waits for the arrival of one of the signals in the
556 * array of signal numbers specified by set, which must be of size
557 * equal to size. If there is a signal already queued, the function
558 * returns immediately. If there is no signal of the specified set
559 * queued, the calling thread is suspended until a signal from that
560 * set arrives. Upon return, if signal_received is not NULL the number
561 * of the signal received is stored in the variable pointed to by
562 * signal_received; and if info is not NULL the associated information
563 * is stored in the variable pointed to by info.
565 * Returns 0 if successful; otherwise it returns an error code:
566 * EINVAL: the array contains one or more values which are not
567 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
570 * Alternatively, in case of error the implementation is allowed to
571 * notify it to the system console and then terminate the FRSH
572 * implementation and dependant applications
575 (frsh_signal_t set[], int size, frsh_signal_t *signal_received,
576 frsh_signal_info_t *info)
582 CHKE(sigemptyset(&signalset));
583 for(i=0;i<size;i++) {
584 CHKE(sigaddset(&signalset,set[i]));
587 err=sigwaitinfo(&signalset,&siginfo);
589 *signal_received=siginfo.si_signo;
590 *info=*((frsh_signal_info_t *)(&siginfo.si_value));
598 * fosa_signal_timedwait()
600 * Timed wait for a signal
602 * This function behaves the same as fosa_signal_wait(), except that
603 * the suspension time is limited to the time interval specified in
604 * the timespec structure referenced by timeout.
606 * Returns 0 if successful; otherwise it returns an error code:
607 * EINVAL: the array contains one or more values which are not
608 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
609 * is less than 0, or timeout is invalid
610 * EAGAIN: The timeout expired
612 * Alternatively, in case of the EINVAL error the implementation is
613 * allowed to notify it to the system console and then terminate the
614 * FRSH implementation and dependant applications
616 int fosa_signal_timedwait
617 (frsh_signal_t set[], int size, frsh_signal_t *signal_received,
618 frsh_signal_info_t *info, const struct timespec *timeout)
621 // the implementation of sigtimedwait is not yet available in MaRTE OS
625 /* sigset_t signalset; */
626 /* siginfo_t siginfo; */
628 /* CHKE(sigemptyset(&signalset)); */
629 /* for(i=0;i<size;i++) { */
630 /* CHKE(sigaddset(&signalset,set[i])); */
633 /* err=sigtimedwait(&signalset,&siginfo,timeout); */
635 /* *signal_received=siginfo.si_signo; */
636 /* *info=siginfo.si_value; */