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 /*************************
65 * Storage of thread-specific keys
66 *************************/
68 static pthread_key_t key_list[FOSA_MAX_KEYS];
69 static bool key_in_use[FOSA_MAX_KEYS];
70 static pthread_mutex_t key_lock;
73 /* Initialize the keys data structure */
77 pthread_mutexattr_t attr;
79 for(i = 0; i < FOSA_MAX_KEYS; i++)
80 key_in_use[i] = false;
82 if ((error = pthread_mutexattr_init(&attr)) != 0)
85 if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0)
88 if ((error = pthread_mutex_init(&key_lock,&attr)) != 0)
91 //if ((error = pthread_mutexattr_destroy(&attr)) != 0)
97 /*************************
98 * Thread identification
99 *************************/
102 * fosa_thread_equal()
104 * Compare two thread identifiers to determine if they refer to the
107 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
109 return t1.linux_pid == t2.linux_pid &&
110 t1.linux_tid == t2.linux_tid &&
111 pthread_equal(t1.pthread_id, t2.pthread_id);
117 * Return the thread id of the calling thread
119 fosa_thread_id_t fosa_thread_self()
121 fosa_thread_id_t thread_self;
124 * fosa_thread_id_t => struct {
125 * pthread_t pthread_id;
130 thread_self.pthread_id = pthread_self();
131 thread_self.linux_pid = getpid();
132 thread_self.linux_tid = syscall(__NR_gettid); /* gettid() */
137 /*************************
139 *************************/
142 * fosa_thread_attr_init()
144 * Initialize a thread attributes object
146 * This function initializes the object pointed to by attr to all
147 * the default values defined by FRSH
149 * return 0 if successful; otherwise it returns
150 * FOSA_ENOMEM: insufficient memory exists to initialize the thread
153 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
155 fosa_thread_id_t self;
157 /* only POSIX threads have attributes */
158 self = fosa_thread_self();
159 if (self.linux_pid == self.linux_tid)
162 return pthread_attr_init(attr);
166 * fosa_thread_attr_destroy()
168 * Destroy a thread attributes object
170 * This function is used to destroy the thread attributes object,
171 * pointed to by attr, and deallocate any system resources allocated for it
175 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
177 fosa_thread_id_t self;
179 /* only POSIX threads can have attributes */
180 self = fosa_thread_self();
181 if (self.linux_pid == self.linux_tid)
184 return pthread_attr_destroy(attr);
188 * fosa_thread_attr_set_stacksize()
190 * Set the thread minimum stack size in a thread attributes object
192 * This function sets the minimum stack size of the thread attributes
193 * object attr to the value given by stacksize, in bytes. This
194 * function has no runtime effect on the stack size, except when the
195 * attributes object is used to create a thread, when it will be
196 * created with the specified minimum stack size
198 * return 0 if successful, or the following error code:
199 * FOSA_EINVAL: the specified stacksize value is not supported in
200 * this implementation
202 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
205 fosa_thread_id_t self;
207 /* only POSIX threads can set the size of the stack */
208 self = fosa_thread_self();
209 if (self.linux_pid == self.linux_tid)
212 return pthread_attr_setstacksize(attr, stacksize);
216 * fosa_thread_attr_get_stacksize()
218 * Get the thread minimum stack size from a thread attributes object
220 * This function sets the variable pointed to by stacksize to the
221 * minimum stack size stored in the thread attributes object attr.
225 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
228 fosa_thread_id_t self;
230 /* only POSIX threads can set the size of the stack */
231 self = fosa_thread_self();
232 if (self.linux_pid == self.linux_tid)
235 return pthread_attr_getstacksize(attr, stacksize);
238 /*************************
239 * Thread creation and termination
240 *************************/
243 * fosa_thread_create()
245 * This function creates a new thread using the attributes specified
246 * in attr. If attr is NULL, default attributes are used. The new
247 * thread starts running immediately, executing the function specified
248 * by code, with an argument equal to arg. Upon successful return, the
249 * variable pointed to by tid will contain the identifier of the newly
250 * created thread. The set of signals that may be synchronously
251 * accepted is inherited from the parent thread.
253 * Returns 0 if successful; otherwise it returs a code error:
255 * EAGAIN: the system lacks the necessary resources to create a
256 * new thread or the maximum number of threads has been
259 * EINVAL: the value specified by attr is invalid (for instance,
260 * it has not been correctly initialized)
262 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
263 * possibly because of incorrect attributes, or because the
264 * requested minimum capacity cannot be guaranteed
266 int fosa_thread_create(fosa_thread_id_t *tid,
267 const fosa_thread_attr_t *attr,
268 fosa_thread_code_t code,
271 return pthread_create(&tid->pthread_id, attr, code, arg);
275 * Note: no thread termination primitive is provided. The termination
276 * of a thread will be notified by the system to the FRSH scheduler
277 * through the scheduler API
280 /**************************************************
281 * Thread-specific data
282 * (extended with access from a different thread)
284 * Several data items (pointers) may be associated with each thread
285 * Each item is identified through a key, an integer value between 0
286 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
287 * deallocating the memory area pointed to by the pointer
288 **************************************************/
293 * Create a new key for thread specific data.
295 * Prior to setting data in a key, we need ask the system to create
298 * return 0 if successful \n
299 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
300 * FOSA_ENOMEM If there are no enough memory resources to
303 int fosa_key_create(int *key)
307 fosa_thread_id_t self;
309 /* only POSIX threads can have specific data */
310 self = fosa_thread_self();
311 if (self.linux_pid == self.linux_tid)
314 if ((error = pthread_mutex_lock(&key_lock)) != 0)
317 /* find an unused key */
318 for (i = 0; i < FOSA_MAX_KEYS; i++) {
319 if (!key_in_use[i]) {
321 key_in_use[i] = true;
322 error = pthread_key_create(&(key_list[i]), NULL);
328 if ((error = pthread_mutex_unlock(&key_lock))!= 0)
331 return (!found ? FOSA_EINVAL : error);
339 * This destroys the key and isables its use in the system
341 * return 0 if successful
342 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
344 int fosa_key_destroy(int key)
347 fosa_thread_id_t self;
349 /* only POSIX threads can have specific data */
350 self = fosa_thread_self();
351 if (self.linux_pid == self.linux_tid)
354 if ((error = pthread_mutex_lock(&key_lock)) != 0)
357 if ((error = pthread_key_delete(key_list[key])) != 0)
358 key_in_use[key]=false;
360 if ((error = pthread_mutex_unlock(&key_lock)) != 0)
368 * fosa_thread_set_specific_data()
370 * Set thread-specific data
372 * For the thread identified by tid, the thread-specifid data field
373 * identified by key will be set to the value specified by value
375 * In this implementation, according to POSIX, the accessed data field
376 * is the one of the calling thread, not the one specified via tid.
378 * Returns 0 if successful; otherwise, an error code is returned
379 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
381 int fosa_thread_set_specific_data(int key,
382 fosa_thread_id_t tid,
385 fosa_thread_id_t self;
387 /* only POSIX threads can have specific data */
388 self = fosa_thread_self();
389 if (self.linux_pid == self.linux_tid)
392 return pthread_setspecific(key_list[key], value);
396 * fosa_thread_get_specific_data()
398 * Get thread-specific data
400 * For the thread identified by tid, the thread-specifid data field
401 * identified by key will be copied to the variable pointed to by value
403 * In this implementation, according to POSIX, the accessed data field
404 * is the one of the calling thread, not the one specified via tid.
406 * Returns 0 if successful; otherwise, an error code is returned
407 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
409 int fosa_thread_get_specific_data(int key,
410 fosa_thread_id_t tid,
413 fosa_thread_id_t self;
415 /* only POSIX threads can have specific data */
416 self = fosa_thread_self();
417 if (self.linux_pid == self.linux_tid)
420 if ((value = pthread_getspecific(key_list[key])) != NULL)
426 /******************************************************************
429 * This implementation of FRSH assumes an underlying fixed priority
430 * scheduler with priorities in a range, with a minimum and a
431 * maximumm, a number of priority levels with at least 31
432 * priorities. A larger number implies a larger priority. In systems
433 * in which the underlying scheduler uses the opposite convention, a
434 * mapping is automatically provided by the OS adaptation layer.
435 *******************************************************************/
438 * fosa_get_priority_max()
440 * Return the maximum priority value used in this implementation
442 int fosa_get_priority_max()
444 return sched_get_priority_max(SCHED_FIFO);
448 * fosa_get_priority_min()
450 * Return the minimum priority value used in this implementation
452 int fosa_get_priority_min()
454 return sched_get_priority_min(SCHED_FIFO);
458 * fosa_thread_attr_set_prio()
460 * Change the priority of a thread attributes object
462 * The priority of the thread attriutes object specified by attr is
463 * set to the value specified by prio. This function has no runtime
464 * effect on the priority, except when the attributes object is used
465 * to create a thread, when it will be created with the specified
468 * Returns 0 if successful, or the following error code:
469 * EINVAL: the specified priority value is not between the
470 * minimum and the maximum priorities defined in this
471 * FRSH implementation
473 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
475 fosa_thread_id_t self;
476 struct sched_param param;
478 /* normal UNIX processes have no attributes */
479 self = fosa_thread_self();
480 if (self.linux_pid == self.linux_tid)
483 param.sched_priority = prio;
485 return pthread_attr_setschedparam(attr, ¶m);
489 * fosa_thread_attr_get_prio()
491 * Get the priority from a thread attributes object
493 * This function sets the variable pointed to by prio to the
494 * priority stored in the thread attributes object attr.
498 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
501 fosa_thread_id_t self;
502 struct sched_param param;
504 /* normal UNIX processes have no attributes */
505 self = fosa_thread_self();
506 if (self.linux_pid == self.linux_tid)
509 if ((error = pthread_attr_getschedparam(attr, ¶m)) == 0)
510 *prio = param.sched_priority;
516 * fosa_thread_set_prio()
518 * Dynamically change the priority of a thread
520 * The priority of the thread identified by tid is
521 * set to the value specified by prio.
523 * Returns 0 if successful, or the following error code:
524 * EINVAL: the specified priority value is not between the
525 * minimum and the maximum priorities defined in this
526 * FRSH implementation
528 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
530 struct sched_param param;
533 param.sched_priority=prio;
534 if (tid.linux_pid == tid.linux_tid)
535 error = sched_setscheduler(tid.linux_pid,
539 error = pthread_setschedparam(tid.pthread_id,
547 * fosa_thread_get_prio()
549 * Dynamically get the priority of a thread
551 * This function sets the variable pointed to by prio to the
552 * priority of the thread identified by tid
556 int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio)
558 struct sched_param param;
561 if (tid.linux_pid == tid.linux_tid)
562 error = sched_getparam(tid.linux_pid, ¶m);
564 error = pthread_getschedparam(tid.pthread_id,
568 *prio = param.sched_priority;
573 /*******************************************************************
576 * Signals represent events that may be notified by the system, or
577 * sent explicitly by the application, and for which a thread may
578 * synchronously wait. Signals carry an associated piece of
579 * information (an integer or a pointer) and are queued until they are
580 * accepted. Signals are identified by an integer signal number (of
581 * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
582 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
584 *******************************************************************/
587 * fosa_set_accepted_signals()
589 * Establish the set of signals that may be synchronously accepted
590 * by the calling thread
592 * The function uses the array of signal numbers specified by set,
593 * which must be of size equal to size
595 * Returns 0 if successful; otherwise it returns an error code:
596 * EINVAL: the array contains one or more values which are not
597 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
600 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
603 fosa_thread_id_t self;
605 struct sigaction action;
607 if ((error = sigemptyset(&sigset)) != 0)
610 /* real-time signal (can be queued) */
611 action.sa_handler = SIG_DFL;
612 action.sa_mask = sigset;
613 action.sa_flags = SA_SIGINFO;
614 action.sa_sigaction = NULL;
616 for (i = 0; i < size; i++) {
617 if ((error = sigaddset(&sigset, set[i])) != 0)
619 if ((error = sigaction(set[i], &action, NULL)) != 0)
623 self = fosa_thread_self();
624 if (self.linux_pid == self.linux_tid)
625 return pthread_sigmask(SIG_BLOCK, &sigset, NULL);
627 return sigprocmask(SIG_BLOCK, &sigset, NULL);
631 * fosa_signal_queue()
635 * This function is used to explicitly send a signal with a specified
638 * The signal number specified by signal is sent together with the
639 * information specified by info, to the thread identified by
642 * Note that, in this implementation, the signal is sent to any thread
643 * waiting for it (maybe via fosa_signal_wait()).
644 * If needed ensure the receiver is the only one who is waiting for the
645 * signal (e.g., by using different signal numbers for each thread).
647 * Returns 0 if successful; otherwise it returns an error code:
648 * EINVAL: the signal specified by signal is not
649 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
651 * EAGAIN: no resources are available to queue the signal; the
652 * maximum number of queued signals has been reached, or a
653 * systemwide resource limit has been exceeded
655 int fosa_signal_queue(fosa_signal_t signal,
656 fosa_signal_info_t info,
657 fosa_thread_id_t receiver)
659 /* Note: signal sent to a "whole" process */
660 return sigqueue(receiver.linux_pid, signal, *((union sigval*) &info));
668 * The function waits for the arrival of one of the signals in the
669 * array of signal numbers specified by set, which must be of size
670 * equal to size. If there is a signal already queued, the function
671 * returns immediately. If there is no signal of the specified set
672 * queued, the calling thread is suspended until a signal from that
673 * set arrives. Upon return, if signal_received is not NULL the number
674 * of the signal received is stored in the variable pointed to by
675 * signal_received; and if info is not NULL the associated information
676 * is stored in the variable pointed to by info.
678 * Returns 0 if successful; otherwise it returns an error code:
679 * EINVAL: the array contains one or more values which are not
680 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
683 int fosa_signal_wait(fosa_signal_t set[], int size,
684 fosa_signal_t *signal_received,
685 fosa_signal_info_t *info)
691 if ((error = sigemptyset(&sigset)) != 0)
694 for (i = 0; i < size; i++)
695 if ((error = sigaddset(&sigset,set[i])) != 0)
698 if ((error = sigwaitinfo(&sigset, &siginfo)) != 0)
701 if (signal_received != NULL)
702 *signal_received = siginfo.si_signo;
704 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
710 * fosa_signal_timedwait()
712 * Timed wait for a signal
714 * This function behaves the same as fosa_signal_wait(), except that
715 * the suspension time is limited to the time interval specified in
716 * the timespec structure referenced by timeout.
718 * Returns 0 if successful; otherwise it returns an error code:
719 * EINVAL: the array contains one or more values which are not
720 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
721 * is less than 0, or timeout is invalid
722 * EAGAIN: The timeout expired
724 int fosa_signal_timedwait(fosa_signal_t set[], int size,
725 fosa_signal_t *signal_received,
726 fosa_signal_info_t *info,
727 const struct timespec *timeout)
733 if ((error = sigemptyset(&signalset)) != 0)
736 for (i = 0; i < size; i++)
737 if ((error = sigaddset(&signalset,set[i])) != 0)
740 if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0)
743 if (signal_received != NULL)
744 *signal_received = siginfo.si_signo;
746 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;