1 // -----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2009 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 //==============================================
56 // ******** ****** ******** **********
57 // **///// /** ** **////// /** /**
58 // ** /** ** /** /** /**
59 // ******* /** ** /********* /**********
60 // **//// /** ** ////////** /**//////**
61 // ** /** ** /** /** /**
62 // ** /** ** ******** /** /**
63 // // /******/ //////// // //
65 // FOSA(Frescor Operating System Adaptation layer)
66 //================================================
68 #include "fosa_time.h"
69 #include "fosa_configuration_parameters.h"
70 #include "fosa_threads_and_signals.h"
72 #ifdef OMK_FOR_USER /* If compiled by OMK, use the config */
73 #include "fosa_config.h"
76 /*************************
77 * Storage of thread-specific keys
78 *************************/
80 static pthread_key_t key_list[FOSA_MAX_KEYS];
81 static bool key_in_use[FOSA_MAX_KEYS];
82 static pthread_mutex_t key_lock;
85 /* Initialize the keys data structure */
89 pthread_mutexattr_t attr;
91 for(i = 0; i < FOSA_MAX_KEYS; i++)
92 key_in_use[i] = false;
94 ret = pthread_mutexattr_init(&attr);
95 if (ret) return errno;
97 #ifndef CONFIG_NO_PRIO_INHERIT /* Not supported on older systems */
98 ret = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
99 if (ret) return errno;
102 ret = pthread_mutex_init(&key_lock,&attr);
103 if (ret) return errno;
108 /*************************
109 * Thread identification
110 *************************/
113 * fosa_thread_equal()
115 * Compare two thread identifiers to determine if they refer to the
118 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
120 return t1.linux_pid == t2.linux_pid &&
121 t1.linux_tid == t2.linux_tid &&
122 pthread_equal(t1.pthread_id, t2.pthread_id);
128 * Return the thread id of the calling thread
130 fosa_thread_id_t fosa_thread_self()
132 fosa_thread_id_t thread_self;
135 * fosa_thread_id_t => struct {
136 * pthread_t pthread_id;
141 thread_self.pthread_id = pthread_self();
142 thread_self.linux_pid = getpid();
143 thread_self.linux_tid = syscall(__NR_gettid); /* gettid() */
148 /*************************
150 *************************/
152 static inline int __fosa_check_thread(const fosa_thread_id_t *tid)
154 if (tid->linux_pid == tid->linux_tid)
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
169 * FOSA_ENOMEM: insufficient memory exists to initialize the thread
172 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
174 return pthread_attr_init(attr);
178 * fosa_thread_attr_destroy()
180 * Destroy a thread attributes object
182 * This function is used to destroy the thread attributes object,
183 * pointed to by attr, and deallocate any system resources allocated for it
187 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
189 return pthread_attr_destroy(attr);
193 * fosa_thread_attr_set_stacksize()
195 * Set the thread minimum stack size in a thread attributes object
197 * This function sets the minimum stack size of the thread attributes
198 * object attr to the value given by stacksize, in bytes. This
199 * function has no runtime effect on the stack size, except when the
200 * attributes object is used to create a thread, when it will be
201 * created with the specified minimum stack size
203 * return 0 if successful, or the following error code:
204 * FOSA_EINVAL: the specified stacksize value is not supported in
205 * this implementation
207 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
210 return pthread_attr_setstacksize(attr, stacksize);
214 * fosa_thread_attr_get_stacksize()
216 * Get the thread minimum stack size from a thread attributes object
218 * This function sets the variable pointed to by stacksize to the
219 * minimum stack size stored in the thread attributes object attr.
223 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
226 return pthread_attr_getstacksize(attr, stacksize);
229 /*************************
230 * Thread creation and termination
231 *************************/
234 * fosa_thread_create()
236 * This function creates a new thread using the attributes specified
237 * in attr. If attr is NULL, default attributes are used. The new
238 * thread starts running immediately, executing the function specified
239 * by code, with an argument equal to arg. Upon successful return, the
240 * variable pointed to by tid will contain the identifier of the newly
241 * created thread. The set of signals that may be synchronously
242 * accepted is inherited from the parent thread.
244 * Returns 0 if successful; otherwise it returs a code error:
246 * EAGAIN: the system lacks the necessary resources to create a
247 * new thread or the maximum number of threads has been
250 * EINVAL: the value specified by attr is invalid (for instance,
251 * it has not been correctly initialized)
253 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
254 * possibly because of incorrect attributes, or because the
255 * requested minimum capacity cannot be guaranteed
257 int fosa_thread_create(fosa_thread_id_t *tid,
258 const fosa_thread_attr_t *attr,
259 fosa_thread_code_t code,
262 return pthread_create(&tid->pthread_id, attr, code, arg);
266 * Note: no thread termination primitive is provided. The termination
267 * of a thread will be notified by the system to the FRSH scheduler
268 * through the scheduler API
271 /**************************************************
272 * Thread-specific data
273 * (extended with access from a different thread)
275 * Several data items (pointers) may be associated with each thread
276 * Each item is identified through a key, an integer value between 0
277 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
278 * deallocating the memory area pointed to by the pointer
279 **************************************************/
284 * Create a new key for thread specific data.
286 * Prior to setting data in a key, we need ask the system to create
289 * return 0 if successful \n
290 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
291 * FOSA_ENOMEM If there are no enough memory resources to
294 int fosa_key_create(int *key)
299 ret = pthread_mutex_lock(&key_lock);
302 /* find an unused key */
303 for (i = 0; i < FOSA_MAX_KEYS; i++) {
304 if (!key_in_use[i]) {
305 ret = pthread_key_create(&(key_list[i]), NULL);
309 key_in_use[i] = true;
316 ret = pthread_mutex_unlock(&key_lock);
319 return (!found ? FOSA_EINVAL : ret);
327 * This destroys the key and isables its use in the system
329 * return 0 if successful
330 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
332 int fosa_key_destroy(int key)
336 ret = pthread_mutex_lock(&key_lock);
339 ret = pthread_key_delete(key_list[key]);
342 key_in_use[key]=false;
344 ret = pthread_mutex_unlock(&key_lock);
352 * fosa_thread_set_specific_data()
354 * Set thread-specific data
356 * For the thread identified by tid, the thread-specifid data field
357 * identified by key will be set to the value specified by value
359 * In this implementation, according to POSIX, the accessed data field
360 * is the one of the calling thread, not the one specified via tid.
362 * Returns 0 if successful; otherwise, an error code is returned
363 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
365 int fosa_thread_set_specific_data(int key,
366 fosa_thread_id_t tid,
371 /* only POSIX threads can have specific data */
372 if (!__fosa_check_thread(&tid))
375 ret = pthread_setspecific(key_list[key], value);
377 return ret ? ret : 0;
381 * fosa_thread_get_specific_data()
383 * Get thread-specific data
385 * For the thread identified by tid, the thread-specifid data field
386 * identified by key will be copied to the variable pointed to by value
388 * In this implementation, according to POSIX, the accessed data field
389 * is the one of the calling thread, not the one specified via tid.
391 * Returns 0 if successful; otherwise, an error code is returned
392 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
394 int fosa_thread_get_specific_data(int key,
395 fosa_thread_id_t tid,
398 /* only POSIX threads can have specific data */
399 if (!__fosa_check_thread(&tid))
402 value = pthread_getspecific(key_list[key]);
404 return !value ? FOSA_EINVAL : 0;
407 /******************************************************************
410 * This implementation of FRSH assumes an underlying fixed priority
411 * scheduler with priorities in a range, with a minimum and a
412 * maximumm, a number of priority levels with at least 31
413 * priorities. A larger number implies a larger priority. In systems
414 * in which the underlying scheduler uses the opposite convention, a
415 * mapping is automatically provided by the OS adaptation layer.
416 *******************************************************************/
419 * fosa_get_priority_max()
421 * Return the maximum priority value used in this implementation
423 int fosa_get_priority_max()
427 ret = sched_get_priority_max(SCHED_RR);
429 return ret ? errno : 0;
433 * fosa_get_priority_min()
435 * Return the minimum priority value used in this implementation
437 int fosa_get_priority_min()
441 ret = sched_get_priority_min(SCHED_RR);
443 return ret ? errno : 0;
447 * fosa_thread_attr_set_prio()
449 * Change the priority of a thread attributes object
451 * The priority of the thread attriutes object specified by attr is
452 * set to the value specified by prio. This function has no runtime
453 * effect on the priority, except when the attributes object is used
454 * to create a thread, when it will be created with the specified
457 * Returns 0 if successful, or the following error code:
458 * EINVAL: the specified priority value is not between the
459 * minimum and the maximum priorities defined in this
460 * FRSH implementation
462 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
465 struct sched_param param;
467 param.sched_priority = prio;
468 ret = pthread_attr_setschedpolicy(attr, SCHED_RR);
471 return pthread_attr_setschedparam(attr, ¶m);
475 * fosa_thread_attr_get_prio()
477 * Get the priority from a thread attributes object
479 * This function sets the variable pointed to by prio to the
480 * priority stored in the thread attributes object attr.
484 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
487 struct sched_param param;
489 ret = pthread_attr_getschedparam(attr, ¶m);
492 *prio = param.sched_priority;
498 * fosa_thread_set_prio()
500 * Dynamically change the priority of a thread
502 * The priority of the thread identified by tid is
503 * set to the value specified by prio.
505 * Returns 0 if successful, or the following error code:
506 * EINVAL: the specified priority value is not between the
507 * minimum and the maximum priorities defined in this
508 * FRSH implementation
510 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
513 struct sched_param param;
515 param.sched_priority = prio;
517 ret = sched_setscheduler(0, SCHED_RR, ¶m);
519 return ret ? errno : 0;
523 * fosa_thread_get_prio()
525 * Dynamically get the priority of a thread
527 * This function sets the variable pointed to by prio to the
528 * priority of the thread identified by tid
532 int fosa_thread_get_prio(fosa_thread_id_t tid, int *prio)
534 struct sched_param param;
537 ret = sched_getparam(0, ¶m);
538 *prio = param.sched_priority;
540 return ret ? errno : 0;
543 /*******************************************************************
546 * Signals represent events that may be notified by the system, or
547 * sent explicitly by the application, and for which a thread may
548 * synchronously wait. Signals carry an associated piece of
549 * information (an integer or a pointer) and are queued until they are
550 * accepted. Signals are identified by an integer signal number (of
551 * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
552 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
554 *******************************************************************/
557 * fosa_set_accepted_signals()
559 * Establish the set of signals that may be synchronously accepted
560 * by the calling thread
562 * The function uses the array of signal numbers specified by set,
563 * which must be of size equal to size
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
574 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
577 fosa_thread_id_t self;
579 struct sigaction action;
581 ret = sigemptyset(&sigset);
584 action.sa_handler = SIG_DFL;
585 action.sa_mask = sigset;
586 action.sa_flags = SA_SIGINFO;
587 action.sa_sigaction = NULL;
589 for (i = 0; i < size; i++) {
590 ret = sigaddset(&sigset, set[i]);
592 ret = sigaction(set[i], &action, NULL);
596 self = fosa_thread_self();
597 if (__fosa_check_thread(&self)) {
598 ret = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
601 ret = sigprocmask(SIG_BLOCK, &sigset, NULL);
611 * fosa_signal_queue()
615 * This function is used to explicitly send a signal with a specified
618 * The signal number specified by signal is sent together with the
619 * information specified by info, to the thread identified by
620 * receiver. In those implementations that do not support queueing a
621 * signal with information to a thread (such as POSIX), the signal may
622 * be sent to any thread that is waiting for this signal via
623 * fosa_signal_wait(). Portability can be ensured by having the receiver
624 * thread be the one who is waiting for the signal.
626 * In this implementation, this limitation has been overcome by means
627 * of the Linux specific capability of sending a timer event directly
628 * to a specific thread. Thus, we program a fake timer to fire immediately
629 * and notify such event to the requested receiver thread.
631 * Returns 0 if successful; otherwise it returns an error code:
632 * EINVAL: the signal specified by signal is not
633 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
635 * EAGAIN: no resources are available to queue the signal; the
636 * maximum number of queued signals has been reached, or a
637 * systemwide resource limit has been exceeded
639 * Alternatively, in case of error the implementation is allowed to
640 * notify it to the system console and then terminate the FRSH
641 * implementation and dependant applications
643 int fosa_signal_queue(fosa_signal_t signal,
644 fosa_signal_info_t info,
645 fosa_thread_id_t receiver)
649 struct itimerspec fake_time;
650 struct sigevent fake_event;
652 ret = timer_create(FOSA_CLOCK_REALTIME, &fake_event, &fake_timer);
655 fake_time.it_value.tv_sec = fake_time.it_value.tv_nsec = 0;
656 fake_time.it_interval.tv_sec = fake_time.it_interval.tv_nsec = 0;
657 fake_event.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
658 fake_event.sigev_signo = SIGRTMIN;
659 fake_event.sigev_value.sival_int = info.sival_int;
660 fake_event._sigev_un._tid = receiver.linux_tid;
662 ret = timer_settime(fake_timer, TIMER_ABSTIME, &fake_time, NULL);
664 timer_delete(fake_timer);
668 ret = timer_delete(fake_timer);
681 * The function waits for the arrival of one of the signals in the
682 * array of signal numbers specified by set, which must be of size
683 * equal to size. If there is a signal already queued, the function
684 * returns immediately. If there is no signal of the specified set
685 * queued, the calling thread is suspended until a signal from that
686 * set arrives. Upon return, if signal_received is not NULL the number
687 * of the signal received is stored in the variable pointed to by
688 * signal_received; and if info is not NULL the associated information
689 * is stored in the variable pointed to by info.
691 * Returns 0 if successful; otherwise it returns an error code:
692 * EINVAL: the array contains one or more values which are not
693 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
696 * Alternatively, in case of error the implementation is allowed to
697 * notify it to the system console and then terminate the FRSH
698 * implementation and dependant applications
700 int fosa_signal_wait(fosa_signal_t set[], int size,
701 fosa_signal_t *signal_received,
702 fosa_signal_info_t *info)
708 ret = sigemptyset(&sigset);
711 for (i = 0; i < size; i++) {
712 ret = sigaddset(&sigset,set[i]);
716 ret = sigwaitinfo(&sigset, &siginfo);
719 if (info != NULL && signal_received != NULL)
720 *signal_received = siginfo.si_signo;
722 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
730 * fosa_signal_timedwait()
732 * Timed wait for a signal
734 * This function behaves the same as fosa_signal_wait(), except that
735 * the suspension time is limited to the time interval specified in
736 * the timespec structure referenced by timeout.
738 * Returns 0 if successful; otherwise it returns an error code:
739 * EINVAL: the array contains one or more values which are not
740 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
741 * is less than 0, or timeout is invalid
742 * EAGAIN: The timeout expired
744 * Alternatively, in case of error the implementation is allowed to
745 * notify it to the system console and then terminate the FRSH
746 * implementation and dependant applications
748 int fosa_signal_timedwait(fosa_signal_t set[], int size,
749 fosa_signal_t *signal_received,
750 fosa_signal_info_t *info,
751 const struct timespec *timeout)
757 ret = sigemptyset(&signalset);
760 for (i = 0; i < size; i++) {
761 ret = sigaddset(&signalset,set[i]);
765 ret = sigtimedwait(&signalset,&siginfo,timeout);
768 if (signal_received != NULL)
769 *signal_received = siginfo.si_signo;
771 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;