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 // As a special exception, if you include this header file into source
41 // files to be compiled, this header file does not by itself cause
42 // the resulting executable to be covered by the GNU General Public
43 // License. This exception does not however invalidate any other
44 // reasons why the executable file might be covered by the GNU General
46 // -----------------------------------------------------------------------
47 //==============================================
48 // ******** ****** ******** **********
49 // **///// /** ** **////// /** /**
50 // ** /** ** /** /** /**
51 // ******* /** ** /********* /**********
52 // **//// /** ** ////////** /**//////**
53 // ** /** ** /** /** /**
54 // ** /** ** ******** /** /**
55 // // /******/ //////// // //
57 // FOSA(Frescor Operating System Adaptation layer)
58 //================================================
60 #include "fosa_time.h"
61 #include "fosa_configuration_parameters.h"
62 #include "fosa_threads_and_signals.h"
64 #ifdef OMK_FOR_USER /* If compiled by OMK, use the config */
65 #include "fosa_config.h"
68 /*************************
69 * Storage of thread-specific keys
70 *************************/
72 static pthread_key_t key_list[FOSA_MAX_KEYS];
73 static bool key_in_use[FOSA_MAX_KEYS];
74 static pthread_mutex_t key_lock;
77 /* Initialize the keys data structure */
81 pthread_mutexattr_t attr;
83 for(i = 0; i < FOSA_MAX_KEYS; i++)
84 key_in_use[i] = false;
86 ret = pthread_mutexattr_init(&attr);
87 if (ret) return errno;
89 #ifndef CONFIG_NO_PRIO_INHERIT /* Not supported on older systems */
90 ret = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
91 if (ret) return errno;
94 ret = pthread_mutex_init(&key_lock,&attr);
95 if (ret) return errno;
100 /*************************
101 * Thread identification
102 *************************/
105 * fosa_thread_equal()
107 * Compare two thread identifiers to determine if they refer to the
110 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
112 return t1.linux_pid == t2.linux_pid &&
113 t1.linux_tid == t2.linux_tid &&
114 pthread_equal(t1.pthread_id, t2.pthread_id);
120 * Return the thread id of the calling thread
122 fosa_thread_id_t fosa_thread_self()
124 fosa_thread_id_t thread_self;
127 * fosa_thread_id_t => struct {
128 * pthread_t pthread_id;
133 thread_self.pthread_id = pthread_self();
134 thread_self.linux_pid = getpid();
135 thread_self.linux_tid = syscall(__NR_gettid); /* gettid() */
140 /*************************
142 *************************/
144 static inline int __fosa_check_thread(const fosa_thread_id_t *tid)
146 if (tid->linux_pid == tid->linux_tid)
153 * fosa_thread_attr_init()
155 * Initialize a thread attributes object
157 * This function initializes the object pointed to by attr to all
158 * the default values defined by FRSH
160 * return 0 if successful; otherwise it returns
161 * FOSA_ENOMEM: insufficient memory exists to initialize the thread
164 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
166 return pthread_attr_init(attr);
170 * fosa_thread_attr_destroy()
172 * Destroy a thread attributes object
174 * This function is used to destroy the thread attributes object,
175 * pointed to by attr, and deallocate any system resources allocated for it
179 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
181 return pthread_attr_destroy(attr);
185 * fosa_thread_attr_set_stacksize()
187 * Set the thread minimum stack size in a thread attributes object
189 * This function sets the minimum stack size of the thread attributes
190 * object attr to the value given by stacksize, in bytes. This
191 * function has no runtime effect on the stack size, except when the
192 * attributes object is used to create a thread, when it will be
193 * created with the specified minimum stack size
195 * return 0 if successful, or the following error code:
196 * FOSA_EINVAL: the specified stacksize value is not supported in
197 * this implementation
199 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
202 return pthread_attr_setstacksize(attr, stacksize);
206 * fosa_thread_attr_get_stacksize()
208 * Get the thread minimum stack size from a thread attributes object
210 * This function sets the variable pointed to by stacksize to the
211 * minimum stack size stored in the thread attributes object attr.
215 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
218 return pthread_attr_getstacksize(attr, stacksize);
221 /*************************
222 * Thread creation and termination
223 *************************/
226 * fosa_thread_create()
228 * This function creates a new thread using the attributes specified
229 * in attr. If attr is NULL, default attributes are used. The new
230 * thread starts running immediately, executing the function specified
231 * by code, with an argument equal to arg. Upon successful return, the
232 * variable pointed to by tid will contain the identifier of the newly
233 * created thread. The set of signals that may be synchronously
234 * accepted is inherited from the parent thread.
236 * Returns 0 if successful; otherwise it returs a code error:
238 * EAGAIN: the system lacks the necessary resources to create a
239 * new thread or the maximum number of threads has been
242 * EINVAL: the value specified by attr is invalid (for instance,
243 * it has not been correctly initialized)
245 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
246 * possibly because of incorrect attributes, or because the
247 * requested minimum capacity cannot be guaranteed
249 int fosa_thread_create(fosa_thread_id_t *tid,
250 const fosa_thread_attr_t *attr,
251 fosa_thread_code_t code,
254 return pthread_create(&tid->pthread_id, attr, code, arg);
258 * Note: no thread termination primitive is provided. The termination
259 * of a thread will be notified by the system to the FRSH scheduler
260 * through the scheduler API
263 /**************************************************
264 * Thread-specific data
265 * (extended with access from a different thread)
267 * Several data items (pointers) may be associated with each thread
268 * Each item is identified through a key, an integer value between 0
269 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
270 * deallocating the memory area pointed to by the pointer
271 **************************************************/
276 * Create a new key for thread specific data.
278 * Prior to setting data in a key, we need ask the system to create
281 * return 0 if successful \n
282 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
283 * FOSA_ENOMEM If there are no enough memory resources to
286 int fosa_key_create(int *key)
291 ret = pthread_mutex_lock(&key_lock);
294 /* find an unused key */
295 for (i = 0; i < FOSA_MAX_KEYS; i++) {
296 if (!key_in_use[i]) {
297 ret = pthread_key_create(&(key_list[i]), NULL);
301 key_in_use[i] = true;
308 ret = pthread_mutex_unlock(&key_lock);
311 return (!found ? FOSA_EINVAL : ret);
319 * This destroys the key and isables its use in the system
321 * return 0 if successful
322 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
324 int fosa_key_destroy(int key)
328 ret = pthread_mutex_lock(&key_lock);
331 ret = pthread_key_delete(key_list[key]);
334 key_in_use[key]=false;
336 ret = pthread_mutex_unlock(&key_lock);
344 * fosa_thread_set_specific_data()
346 * Set thread-specific data
348 * For the thread identified by tid, the thread-specifid data field
349 * identified by key will be set to the value specified by value
351 * In this implementation, according to POSIX, the accessed data field
352 * is the one of the calling thread, not the one specified via tid.
354 * Returns 0 if successful; otherwise, an error code is returned
355 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
357 int fosa_thread_set_specific_data(int key,
358 fosa_thread_id_t tid,
363 /* only POSIX threads can have specific data */
364 if (!__fosa_check_thread(&tid))
367 ret = pthread_setspecific(key_list[key], value);
369 return ret ? ret : 0;
373 * fosa_thread_get_specific_data()
375 * Get thread-specific data
377 * For the thread identified by tid, the thread-specifid data field
378 * identified by key will be copied to the variable pointed to by value
380 * In this implementation, according to POSIX, the accessed data field
381 * is the one of the calling thread, not the one specified via tid.
383 * Returns 0 if successful; otherwise, an error code is returned
384 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
386 int fosa_thread_get_specific_data(int key,
387 fosa_thread_id_t tid,
390 /* only POSIX threads can have specific data */
391 if (!__fosa_check_thread(&tid))
394 value = pthread_getspecific(key_list[key]);
396 return !value ? FOSA_EINVAL : 0;
399 /******************************************************************
402 * This implementation of FRSH assumes an underlying fixed priority
403 * scheduler with priorities in a range, with a minimum and a
404 * maximumm, a number of priority levels with at least 31
405 * priorities. A larger number implies a larger priority. In systems
406 * in which the underlying scheduler uses the opposite convention, a
407 * mapping is automatically provided by the OS adaptation layer.
408 *******************************************************************/
411 * fosa_get_priority_max()
413 * Return the maximum priority value used in this implementation
415 int fosa_get_priority_max()
419 ret = sched_get_priority_max(SCHED_RR);
421 return ret ? errno : 0;
425 * fosa_get_priority_min()
427 * Return the minimum priority value used in this implementation
429 int fosa_get_priority_min()
433 ret = sched_get_priority_min(SCHED_RR);
435 return ret ? errno : 0;
439 * fosa_thread_attr_set_prio()
441 * Change the priority of a thread attributes object
443 * The priority of the thread attriutes object specified by attr is
444 * set to the value specified by prio. This function has no runtime
445 * effect on the priority, except when the attributes object is used
446 * to create a thread, when it will be created with the specified
449 * Returns 0 if successful, or the following error code:
450 * EINVAL: the specified priority value is not between the
451 * minimum and the maximum priorities defined in this
452 * FRSH implementation
454 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
457 struct sched_param param;
459 param.sched_priority = prio;
460 ret = pthread_attr_setschedpolicy(attr, SCHED_RR);
463 return pthread_attr_setschedparam(attr, ¶m);
467 * fosa_thread_attr_get_prio()
469 * Get the priority from a thread attributes object
471 * This function sets the variable pointed to by prio to the
472 * priority stored in the thread attributes object attr.
476 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
479 struct sched_param param;
481 ret = pthread_attr_getschedparam(attr, ¶m);
484 *prio = param.sched_priority;
490 * fosa_thread_set_prio()
492 * Dynamically change the priority of a thread
494 * The priority of the thread identified by tid is
495 * set to the value specified by prio.
497 * Returns 0 if successful, or the following error code:
498 * EINVAL: the specified priority value is not between the
499 * minimum and the maximum priorities defined in this
500 * FRSH implementation
502 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
505 struct sched_param param;
507 param.sched_priority = prio;
509 ret = sched_setscheduler(0, SCHED_RR, ¶m);
511 return ret ? errno : 0;
515 * fosa_thread_get_prio()
517 * Dynamically get the priority of a thread
519 * This function sets the variable pointed to by prio to the
520 * priority of the thread identified by tid
524 int fosa_thread_get_prio(fosa_thread_id_t tid, int *prio)
526 struct sched_param param;
529 ret = sched_getparam(0, ¶m);
530 *prio = param.sched_priority;
532 return ret ? errno : 0;
535 /*******************************************************************
538 * Signals represent events that may be notified by the system, or
539 * sent explicitly by the application, and for which a thread may
540 * synchronously wait. Signals carry an associated piece of
541 * information (an integer or a pointer) and are queued until they are
542 * accepted. Signals are identified by an integer signal number (of
543 * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
544 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
546 *******************************************************************/
549 * fosa_set_accepted_signals()
551 * Establish the set of signals that may be synchronously accepted
552 * by the calling thread
554 * The function uses the array of signal numbers specified by set,
555 * which must be of size equal to size
557 * Returns 0 if successful; otherwise it returns an error code:
558 * EINVAL: the array contains one or more values which are not
559 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
562 * Alternatively, in case of error the implementation is allowed to
563 * notify it to the system console and then terminate the FRSH
564 * implementation and dependant applications
566 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
569 fosa_thread_id_t self;
571 struct sigaction action;
573 ret = sigemptyset(&sigset);
576 action.sa_handler = SIG_DFL;
577 action.sa_mask = sigset;
578 action.sa_flags = SA_SIGINFO;
579 action.sa_sigaction = NULL;
581 for (i = 0; i < size; i++) {
582 ret = sigaddset(&sigset, set[i]);
584 ret = sigaction(set[i], &action, NULL);
588 self = fosa_thread_self();
589 if (__fosa_check_thread(&self)) {
590 ret = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
593 ret = sigprocmask(SIG_BLOCK, &sigset, NULL);
603 * fosa_signal_queue()
607 * This function is used to explicitly send a signal with a specified
610 * The signal number specified by signal is sent together with the
611 * information specified by info, to the thread identified by
612 * receiver. In those implementations that do not support queueing a
613 * signal with information to a thread (such as POSIX), the signal may
614 * be sent to any thread that is waiting for this signal via
615 * fosa_signal_wait(). Portability can be ensured by having the receiver
616 * thread be the one who is waiting for the signal.
618 * In this implementation, this limitation has been overcome by means
619 * of the Linux specific capability of sending a timer event directly
620 * to a specific thread. Thus, we program a fake timer to fire immediately
621 * and notify such event to the requested receiver thread.
623 * Returns 0 if successful; otherwise it returns an error code:
624 * EINVAL: the signal specified by signal is not
625 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
627 * EAGAIN: no resources are available to queue the signal; the
628 * maximum number of queued signals has been reached, or a
629 * systemwide resource limit has been exceeded
631 * Alternatively, in case of error the implementation is allowed to
632 * notify it to the system console and then terminate the FRSH
633 * implementation and dependant applications
635 int fosa_signal_queue(fosa_signal_t signal,
636 fosa_signal_info_t info,
637 fosa_thread_id_t receiver)
641 struct itimerspec fake_time;
642 struct sigevent fake_event;
644 ret = timer_create(FOSA_CLOCK_REALTIME, &fake_event, &fake_timer);
647 fake_time.it_value.tv_sec = fake_time.it_value.tv_nsec = 0;
648 fake_time.it_interval.tv_sec = fake_time.it_interval.tv_nsec = 0;
649 fake_event.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
650 fake_event.sigev_signo = SIGRTMIN;
651 fake_event.sigev_value.sival_int = info.sival_int;
652 fake_event._sigev_un._tid = receiver.linux_tid;
654 ret = timer_settime(fake_timer, TIMER_ABSTIME, &fake_time, NULL);
656 timer_delete(fake_timer);
660 ret = timer_delete(fake_timer);
673 * The function waits for the arrival of one of the signals in the
674 * array of signal numbers specified by set, which must be of size
675 * equal to size. If there is a signal already queued, the function
676 * returns immediately. If there is no signal of the specified set
677 * queued, the calling thread is suspended until a signal from that
678 * set arrives. Upon return, if signal_received is not NULL the number
679 * of the signal received is stored in the variable pointed to by
680 * signal_received; and if info is not NULL the associated information
681 * is stored in the variable pointed to by info.
683 * Returns 0 if successful; otherwise it returns an error code:
684 * EINVAL: the array contains one or more values which are not
685 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
688 * Alternatively, in case of error the implementation is allowed to
689 * notify it to the system console and then terminate the FRSH
690 * implementation and dependant applications
692 int fosa_signal_wait(fosa_signal_t set[], int size,
693 fosa_signal_t *signal_received,
694 fosa_signal_info_t *info)
700 ret = sigemptyset(&sigset);
703 for (i = 0; i < size; i++) {
704 ret = sigaddset(&sigset,set[i]);
708 ret = sigwaitinfo(&sigset, &siginfo);
711 if (info != NULL && signal_received != NULL)
712 *signal_received = siginfo.si_signo;
714 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
722 * fosa_signal_timedwait()
724 * Timed wait for a signal
726 * This function behaves the same as fosa_signal_wait(), except that
727 * the suspension time is limited to the time interval specified in
728 * the timespec structure referenced by timeout.
730 * Returns 0 if successful; otherwise it returns an error code:
731 * EINVAL: the array contains one or more values which are not
732 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
733 * is less than 0, or timeout is invalid
734 * EAGAIN: The timeout expired
736 * Alternatively, in case of error the implementation is allowed to
737 * notify it to the system console and then terminate the FRSH
738 * implementation and dependant applications
740 int fosa_signal_timedwait(fosa_signal_t set[], int size,
741 fosa_signal_t *signal_received,
742 fosa_signal_info_t *info,
743 const struct timespec *timeout)
749 ret = sigemptyset(&signalset);
752 for (i = 0; i < size; i++) {
753 ret = sigaddset(&signalset,set[i]);
757 ret = sigtimedwait(&signalset,&siginfo,timeout);
760 if (signal_received != NULL)
761 *signal_received = siginfo.si_signo;
763 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;