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_threads_and_signals.h"
61 #include "fosa_configuration_parameters.h"
63 /*************************
64 * Storage of thread-specific keys
65 *************************/
67 static pthread_key_t key_list[FOSA_MAX_KEYS];
68 static bool key_in_use[FOSA_MAX_KEYS];
69 static pthread_mutex_t key_lock;
72 /* Initialize the keys data structure */
76 pthread_mutexattr_t attr;
78 for(i = 0; i < FOSA_MAX_KEYS; i++)
79 key_in_use[i] = false;
81 if ((error = pthread_mutexattr_init(&attr)) != 0)
84 if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0)
87 if ((error = pthread_mutex_init(&key_lock,&attr)) != 0)
90 //if ((error = pthread_mutexattr_destroy(&attr)) != 0)
96 /*************************
97 * Thread identification
98 *************************/
101 * fosa_thread_equal()
103 * Compare two thread identifiers to determine if they refer to the
106 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
108 return t1.linux_pid == t2.linux_pid &&
109 t1.linux_tid == t2.linux_tid &&
110 pthread_equal(t1.pthread_id, t2.pthread_id);
116 * Return the thread id of the calling thread
118 fosa_thread_id_t fosa_thread_self()
120 fosa_thread_id_t thread_self;
123 * fosa_thread_id_t => struct {
124 * pthread_t pthread_id;
129 thread_self.pthread_id = pthread_self();
130 thread_self.linux_pid = getpid();
131 thread_self.linux_tid = syscall(__NR_gettid); /* gettid() */
136 /*************************
138 *************************/
141 * fosa_thread_attr_init()
143 * Initialize a thread attributes object
145 * This function initializes the object pointed to by attr to all
146 * the default values defined by FRSH
148 * return 0 if successful; otherwise it returns
149 * FOSA_ENOMEM: insufficient memory exists to initialize the thread
152 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
154 fosa_thread_id_t self;
156 /* only POSIX threads have attributes */
157 self = fosa_thread_self();
158 if (self.linux_pid == self.linux_tid)
161 return pthread_attr_init(attr);
165 * fosa_thread_attr_destroy()
167 * Destroy a thread attributes object
169 * This function is used to destroy the thread attributes object,
170 * pointed to by attr, and deallocate any system resources allocated for it
174 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
176 fosa_thread_id_t self;
178 /* only POSIX threads can have attributes */
179 self = fosa_thread_self();
180 if (self.linux_pid == self.linux_tid)
183 return pthread_attr_destroy(attr);
187 * fosa_thread_attr_set_stacksize()
189 * Set the thread minimum stack size in a thread attributes object
191 * This function sets the minimum stack size of the thread attributes
192 * object attr to the value given by stacksize, in bytes. This
193 * function has no runtime effect on the stack size, except when the
194 * attributes object is used to create a thread, when it will be
195 * created with the specified minimum stack size
197 * return 0 if successful, or the following error code:
198 * FOSA_EINVAL: the specified stacksize value is not supported in
199 * this implementation
201 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
204 fosa_thread_id_t self;
206 /* only POSIX threads can set the size of the stack */
207 self = fosa_thread_self();
208 if (self.linux_pid == self.linux_tid)
211 return pthread_attr_setstacksize(attr, stacksize);
215 * fosa_thread_attr_get_stacksize()
217 * Get the thread minimum stack size from a thread attributes object
219 * This function sets the variable pointed to by stacksize to the
220 * minimum stack size stored in the thread attributes object attr.
224 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
227 fosa_thread_id_t self;
229 /* only POSIX threads can set the size of the stack */
230 self = fosa_thread_self();
231 if (self.linux_pid == self.linux_tid)
234 return pthread_attr_getstacksize(attr, stacksize);
237 /*************************
238 * Thread creation and termination
239 *************************/
242 * fosa_thread_create()
244 * This function creates a new thread using the attributes specified
245 * in attr. If attr is NULL, default attributes are used. The new
246 * thread starts running immediately, executing the function specified
247 * by code, with an argument equal to arg. Upon successful return, the
248 * variable pointed to by tid will contain the identifier of the newly
249 * created thread. The set of signals that may be synchronously
250 * accepted is inherited from the parent thread.
252 * Returns 0 if successful; otherwise it returs a code error:
254 * EAGAIN: the system lacks the necessary resources to create a
255 * new thread or the maximum number of threads has been
258 * EINVAL: the value specified by attr is invalid (for instance,
259 * it has not been correctly initialized)
261 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
262 * possibly because of incorrect attributes, or because the
263 * requested minimum capacity cannot be guaranteed
265 int fosa_thread_create(fosa_thread_id_t *tid,
266 const fosa_thread_attr_t *attr,
267 fosa_thread_code_t code,
270 return pthread_create(&tid->pthread_id, attr, code, arg);
274 * Note: no thread termination primitive is provided. The termination
275 * of a thread will be notified by the system to the FRSH scheduler
276 * through the scheduler API
279 /**************************************************
280 * Thread-specific data
281 * (extended with access from a different thread)
283 * Several data items (pointers) may be associated with each thread
284 * Each item is identified through a key, an integer value between 0
285 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
286 * deallocating the memory area pointed to by the pointer
287 **************************************************/
292 * Create a new key for thread specific data.
294 * Prior to setting data in a key, we need ask the system to create
297 * return 0 if successful \n
298 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
299 * FOSA_ENOMEM If there are no enough memory resources to
302 int fosa_key_create(int *key)
306 fosa_thread_id_t self;
308 /* only POSIX threads can have specific data */
309 self = fosa_thread_self();
310 if (self.linux_pid == self.linux_tid)
313 if ((error = pthread_mutex_lock(&key_lock)) != 0)
316 /* find an unused key */
317 for (i = 0; i < FOSA_MAX_KEYS; i++) {
318 if (!key_in_use[i]) {
320 key_in_use[i] = true;
321 error = pthread_key_create(&(key_list[i]), NULL);
327 if ((error = pthread_mutex_unlock(&key_lock))!= 0)
330 return (!found ? FOSA_EINVAL : error);
338 * This destroys the key and isables its use in the system
340 * return 0 if successful
341 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
343 int fosa_key_destroy(int key)
346 fosa_thread_id_t self;
348 /* only POSIX threads can have specific data */
349 self = fosa_thread_self();
350 if (self.linux_pid == self.linux_tid)
353 if ((error = pthread_mutex_lock(&key_lock)) != 0)
356 if ((error = pthread_key_delete(key_list[key])) != 0)
357 key_in_use[key]=false;
359 if ((error = pthread_mutex_unlock(&key_lock)) != 0)
367 * fosa_thread_set_specific_data()
369 * Set thread-specific data
371 * For the thread identified by tid, the thread-specifid data field
372 * identified by key will be set to the value specified by value
374 * In this implementation, according to POSIX, the accessed data field
375 * is the one of the calling thread, not the one specified via tid.
377 * Returns 0 if successful; otherwise, an error code is returned
378 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
380 int fosa_thread_set_specific_data(int key,
381 fosa_thread_id_t tid,
384 fosa_thread_id_t self;
386 /* only POSIX threads can have specific data */
387 self = fosa_thread_self();
388 if (self.linux_pid == self.linux_tid)
391 return pthread_setspecific(key_list[key], value);
395 * fosa_thread_get_specific_data()
397 * Get thread-specific data
399 * For the thread identified by tid, the thread-specifid data field
400 * identified by key will be copied to the variable pointed to by value
402 * In this implementation, according to POSIX, the accessed data field
403 * is the one of the calling thread, not the one specified via tid.
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 int fosa_thread_get_specific_data(int key,
409 fosa_thread_id_t tid,
412 fosa_thread_id_t self;
414 /* only POSIX threads can have specific data */
415 self = fosa_thread_self();
416 if (self.linux_pid == self.linux_tid)
419 if ((value = pthread_getspecific(key_list[key])) != NULL)
425 /******************************************************************
428 * This implementation of FRSH assumes an underlying fixed priority
429 * scheduler with priorities in a range, with a minimum and a
430 * maximumm, a number of priority levels with at least 31
431 * priorities. A larger number implies a larger priority. In systems
432 * in which the underlying scheduler uses the opposite convention, a
433 * mapping is automatically provided by the OS adaptation layer.
434 *******************************************************************/
437 * fosa_get_priority_max()
439 * Return the maximum priority value used in this implementation
441 int fosa_get_priority_max()
443 return sched_get_priority_max(SCHED_FIFO);
447 * fosa_get_priority_min()
449 * Return the minimum priority value used in this implementation
451 int fosa_get_priority_min()
453 return sched_get_priority_min(SCHED_FIFO);
457 * fosa_thread_attr_set_prio()
459 * Change the priority of a thread attributes object
461 * The priority of the thread attriutes object specified by attr is
462 * set to the value specified by prio. This function has no runtime
463 * effect on the priority, except when the attributes object is used
464 * to create a thread, when it will be created with the specified
467 * Returns 0 if successful, or the following error code:
468 * EINVAL: the specified priority value is not between the
469 * minimum and the maximum priorities defined in this
470 * FRSH implementation
472 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
474 fosa_thread_id_t self;
475 struct sched_param param;
477 /* normal UNIX processes have no attributes */
478 self = fosa_thread_self();
479 if (self.linux_pid == self.linux_tid)
482 param.sched_priority = prio;
484 return pthread_attr_setschedparam(attr, ¶m);
488 * fosa_thread_attr_get_prio()
490 * Get the priority from a thread attributes object
492 * This function sets the variable pointed to by prio to the
493 * priority stored in the thread attributes object attr.
497 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
500 fosa_thread_id_t self;
501 struct sched_param param;
503 /* normal UNIX processes have no attributes */
504 self = fosa_thread_self();
505 if (self.linux_pid == self.linux_tid)
508 if ((error = pthread_attr_getschedparam(attr, ¶m)) == 0)
509 *prio = param.sched_priority;
515 * fosa_thread_set_prio()
517 * Dynamically change the priority of a thread
519 * The priority of the thread identified by tid is
520 * set to the value specified by prio.
522 * Returns 0 if successful, or the following error code:
523 * EINVAL: the specified priority value is not between the
524 * minimum and the maximum priorities defined in this
525 * FRSH implementation
527 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
529 struct sched_param param;
532 param.sched_priority=prio;
533 if (tid.linux_pid == tid.linux_tid)
534 error = sched_setscheduler(tid.linux_pid,
538 error = pthread_setschedparam(tid.pthread_id,
546 * fosa_thread_get_prio()
548 * Dynamically get the priority of a thread
550 * This function sets the variable pointed to by prio to the
551 * priority of the thread identified by tid
555 int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio)
557 struct sched_param param;
560 if (tid.linux_pid == tid.linux_tid)
561 error = sched_getparam(tid.linux_pid, ¶m);
563 error = pthread_getschedparam(tid.pthread_id,
567 *prio = param.sched_priority;
572 /*******************************************************************
575 * Signals represent events that may be notified by the system, or
576 * sent explicitly by the application, and for which a thread may
577 * synchronously wait. Signals carry an associated piece of
578 * information (an integer or a pointer) and are queued until they are
579 * accepted. Signals are identified by an integer signal number (of
580 * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
581 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
583 *******************************************************************/
586 * fosa_set_accepted_signals()
588 * Establish the set of signals that may be synchronously accepted
589 * by the calling thread
591 * The function uses the array of signal numbers specified by set,
592 * which must be of size equal to size
594 * Returns 0 if successful; otherwise it returns an error code:
595 * EINVAL: the array contains one or more values which are not
596 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
599 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
602 fosa_thread_id_t self;
604 struct sigaction action;
606 if ((error = sigemptyset(&sigset)) != 0)
609 /* real-time signal (can be queued) */
610 action.sa_handler = SIG_DFL;
611 action.sa_mask = sigset;
612 action.sa_flags = SA_SIGINFO;
613 action.sa_sigaction = NULL;
615 for (i = 0; i < size; i++) {
616 if ((error = sigaddset(&sigset, set[i])) != 0)
618 if ((error = sigaction(set[i], &action, NULL)) != 0)
622 self = fosa_thread_self();
623 if (self.linux_pid == self.linux_tid)
624 return pthread_sigmask(SIG_BLOCK, &sigset, NULL);
626 return sigprocmask(SIG_BLOCK, &sigset, NULL);
630 * fosa_signal_queue()
634 * This function is used to explicitly send a signal with a specified
637 * The signal number specified by signal is sent together with the
638 * information specified by info, to the thread identified by
641 * Note that, in this implementation, the signal is sent to any thread
642 * waiting for it (maybe via fosa_signal_wait()).
643 * If needed ensure the receiver is the only one who is waiting for the
644 * signal (e.g., by using different signal numbers for each thread).
646 * Returns 0 if successful; otherwise it returns an error code:
647 * EINVAL: the signal specified by signal is not
648 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
650 * EAGAIN: no resources are available to queue the signal; the
651 * maximum number of queued signals has been reached, or a
652 * systemwide resource limit has been exceeded
654 int fosa_signal_queue(fosa_signal_t signal,
655 fosa_signal_info_t info,
656 fosa_thread_id_t receiver)
658 /* Note: signal sent to a "whole" process */
659 return sigqueue(receiver.linux_pid, signal, *((union sigval*) &info));
667 * The function waits for the arrival of one of the signals in the
668 * array of signal numbers specified by set, which must be of size
669 * equal to size. If there is a signal already queued, the function
670 * returns immediately. If there is no signal of the specified set
671 * queued, the calling thread is suspended until a signal from that
672 * set arrives. Upon return, if signal_received is not NULL the number
673 * of the signal received is stored in the variable pointed to by
674 * signal_received; and if info is not NULL the associated information
675 * is stored in the variable pointed to by info.
677 * Returns 0 if successful; otherwise it returns an error code:
678 * EINVAL: the array contains one or more values which are not
679 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
682 int fosa_signal_wait(fosa_signal_t set[], int size,
683 fosa_signal_t *signal_received,
684 fosa_signal_info_t *info)
690 if ((error = sigemptyset(&sigset)) != 0)
693 for (i = 0; i < size; i++)
694 if ((error = sigaddset(&sigset,set[i])) != 0)
697 if ((error = sigwaitinfo(&sigset, &siginfo)) != 0)
700 if (signal_received != NULL)
701 *signal_received = siginfo.si_signo;
703 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
709 * fosa_signal_timedwait()
711 * Timed wait for a signal
713 * This function behaves the same as fosa_signal_wait(), except that
714 * the suspension time is limited to the time interval specified in
715 * the timespec structure referenced by timeout.
717 * Returns 0 if successful; otherwise it returns an error code:
718 * EINVAL: the array contains one or more values which are not
719 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
720 * is less than 0, or timeout is invalid
721 * EAGAIN: The timeout expired
723 int fosa_signal_timedwait(fosa_signal_t set[], int size,
724 fosa_signal_t *signal_received,
725 fosa_signal_info_t *info,
726 const struct timespec *timeout)
732 if ((error = sigemptyset(&signalset)) != 0)
735 for (i = 0; i < size; i++)
736 if ((error = sigaddset(&signalset,set[i])) != 0)
739 if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0)
742 if (signal_received != NULL)
743 *signal_received = siginfo.si_signo;
745 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;