]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_aquosa/fosa_threads_and_signals.c
Bugfixes and restyling.
[frescor/fosa.git] / src_aquosa / fosa_threads_and_signals.c
1 // -----------------------------------------------------------------------
2 //  Copyright (C) 2006 - 2007 FRESCOR consortium partners:
3 //
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
10 //    ENEA                                   SWEDEN
11 //    Thales Communication S.A.              FRANCE
12 //    Visual Tools S.A.                      SPAIN
13 //    Rapita Systems Ltd                     UK
14 //    Evidence                               ITALY
15 //    
16 //    See http://www.frescor.org for a link to partners' websites
17 //
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
21 //        made of this code.
22 //
23 //  This file is part of the FRSH implementation
24 //
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)
28 //  any later version.
29 //
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.
34 //
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
38 //  02111-1307, USA.
39 //
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
45 //  Public License.
46 // -----------------------------------------------------------------------
47 //==============================================
48 //  ********  ******    ********  **********
49 //  **///// /**    **  **//////  /**     /**
50 //  **      /**    ** /**        /**     /**
51 //  ******* /**    ** /********* /**********
52 //  **////  /**    ** ////////** /**//////**
53 //  **      /**    **        /** /**     /**
54 //  **      /**    **  ********  /**     /**
55 //  //       /******/  ////////   //      // 
56 //
57 // FOSA(Frescor Operating System Adaptation layer)
58 //================================================
59
60 #include "fosa_time.h"
61 #include "fosa_configuration_parameters.h"
62 #include "fosa_threads_and_signals.h"
63
64 /*************************
65  * Storage of thread-specific keys
66  *************************/
67
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;
71
72
73 /* Initialize the keys data structure */
74 int init_keys()
75 {
76         int i, error;
77         pthread_mutexattr_t attr;
78
79         for(i = 0; i < FOSA_MAX_KEYS; i++)
80                 key_in_use[i] = false;
81
82         if ((error = pthread_mutexattr_init(&attr)) != 0)
83                 return error;
84
85         if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0)
86                 return error;
87
88         if ((error = pthread_mutex_init(&key_lock,&attr)) != 0)
89                 return error;
90
91         return 0;
92 }
93
94 /*************************
95  * Thread identification
96  *************************/ 
97
98 /**
99  * fosa_thread_equal()
100  *
101  * Compare two thread identifiers to determine if they refer to the 
102  * same thread
103  **/
104 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
105 {
106         return t1.linux_pid == t2.linux_pid &&
107                t1.linux_tid == t2.linux_tid &&
108                pthread_equal(t1.pthread_id, t2.pthread_id);
109 }
110
111 /**
112  * fosa_thread_self()
113  *
114  * Return the thread id of the calling thread
115  **/
116 fosa_thread_id_t fosa_thread_self()
117 {
118         fosa_thread_id_t thread_self;
119         /** 
120          * NB. Remember:
121          *  fosa_thread_id_t => struct {
122          *                       pthread_t pthread_id;
123          *                       pid_t linux_pid;
124          *                       tid_t linux_tid;
125          * };
126          **/
127         thread_self.pthread_id = pthread_self();
128         thread_self.linux_pid = getpid();
129         thread_self.linux_tid = syscall(__NR_gettid);   /* gettid() */
130
131         return thread_self;
132 }
133
134 /*************************
135  * Thread attributes
136  *************************/
137
138 static inline int __fosa_check_thread(const fosa_thread_id_t *tid)
139 {
140         if (tid->linux_pid == tid->linux_tid)
141                 return 0;
142
143         return 1;
144 }
145
146 /**
147  * fosa_thread_attr_init()
148  *
149  * Initialize a thread attributes object
150  *
151  * This function initializes the object pointed to by attr to all 
152  * the default values defined by FRSH
153  *
154  * return 0 if successful; otherwise it returns
155  *   FOSA_ENOMEM: insufficient memory exists to initialize the thread 
156  *           attributes object
157  **/
158 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
159 {
160         return pthread_attr_init(attr);
161 }
162
163 /**
164  * fosa_thread_attr_destroy()
165  *
166  * Destroy a thread attributes object
167  *
168  * This function is used to destroy the thread attributes object,
169  * pointed to by attr, and deallocate any system resources allocated for it
170  * 
171  * Returns 0
172  **/
173 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
174 {
175         return pthread_attr_destroy(attr);
176 }
177
178 /**
179  * fosa_thread_attr_set_stacksize()
180  *
181  * Set the thread minimum stack size in a thread attributes object
182  *
183  * This function sets the minimum stack size of the thread attributes
184  * object attr to the value given by stacksize, in bytes. This
185  * function has no runtime effect on the stack size, except when the
186  * attributes object is used to create a thread, when it will be
187  * created with the specified minimum stack size
188  * 
189  * return 0 if successful, or the following error code:
190  *    FOSA_EINVAL: the specified stacksize  value is not supported in
191  *            this implementation
192  **/
193 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
194                                    size_t stacksize)
195 {
196         return pthread_attr_setstacksize(attr, stacksize);
197 }
198
199 /**
200  * fosa_thread_attr_get_stacksize()
201  *
202  * Get the thread minimum stack size from a thread attributes object
203  *
204  * This function sets the variable pointed to by stacksize to the
205  * minimum stack size stored in the thread attributes object attr.
206  * 
207  * return 0
208  **/
209 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
210                                    size_t *stacksize)
211 {
212         return pthread_attr_getstacksize(attr, stacksize);
213 }
214
215 /*************************
216  * Thread creation and termination
217  *************************/
218
219 /**
220  * fosa_thread_create()
221  *
222  * This function creates a new thread using the attributes specified
223  * in attr. If attr is NULL, default attributes are used. The new
224  * thread starts running immediately, executing the function specified
225  * by code, with an argument equal to arg. Upon successful return, the
226  * variable pointed to by tid will contain the identifier of the newly
227  * created thread. The set of signals that may be synchronously
228  * accepted is inherited from the parent thread.
229  *
230  * Returns 0 if successful; otherwise it returs a code error:
231  *
232  *     EAGAIN: the system lacks the necessary resources to create a
233  *             new thread or the maximum number of threads has been
234  *             reached
235  *
236  *     EINVAL: the value specified by attr is invalid (for instance,
237  *              it has not been correctly initialized)
238  *
239  *     EREJECT: the cretion of the thread was rejected by the frsh scheduler
240  *               possibly because of incorrect attributes, or because the 
241  *               requested minimum capacity cannot be guaranteed
242  **/
243 int fosa_thread_create(fosa_thread_id_t *tid,
244                        const fosa_thread_attr_t *attr,
245                        fosa_thread_code_t code,
246                        void *arg)
247 {
248         return pthread_create(&tid->pthread_id, attr, code, arg);
249 }
250
251 /**
252  * Note: no thread termination primitive is provided. The termination
253  * of a thread will be notified by the system to the FRSH scheduler
254  * through the scheduler API
255  **/
256
257 /**************************************************
258  * Thread-specific data
259  *  (extended with access from a different thread)
260  *
261  * Several data items (pointers) may be associated with each thread
262  * Each item is identified through a key, an integer value between 0
263  * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
264  * deallocating the memory area pointed to by the pointer
265  **************************************************/ 
266
267 /**
268  * fosa_key_create()
269  *
270  * Create a new key for thread specific data.
271  *
272  * Prior to setting data in a key, we need ask the system to create
273  * one for us.
274  *
275  * return 0 if successful \n
276  *   FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
277  *   FOSA_ENOMEM If there are no enough memory resources to 
278  *               create the key.
279  **/
280 int fosa_key_create(int *key)
281 {
282         int i, error = 0;
283         bool found = false;
284
285         if ((error = pthread_mutex_lock(&key_lock)) != 0)
286                 return error;
287
288         /* find an unused key */
289         for (i = 0; i < FOSA_MAX_KEYS; i++) {
290                 if (!key_in_use[i]) {
291                         *key = i;
292                         key_in_use[i] = true;
293                         error = pthread_key_create(&(key_list[i]), NULL);
294                         found = true;
295                         break;
296                 }
297         }
298
299         if ((error = pthread_mutex_unlock(&key_lock))!= 0)
300                 return error;
301
302         return (!found ? FOSA_EINVAL : error);
303 }
304
305 /**
306  * fosa_key_destroy()
307  *
308  * Destroy a key
309  *
310  * This destroys the key and isables its use in the system
311  *
312  * return 0 if successful
313  *   FOSA_EINVAL The key is not initialised or is not in FOSA key range.
314  **/
315 int fosa_key_destroy(int key)
316 {
317         int error;
318
319         if ((error = pthread_mutex_lock(&key_lock)) != 0)
320                 return error;
321
322         if ((error = pthread_key_delete(key_list[key])) != 0)
323                 key_in_use[key]=false;
324
325         if ((error = pthread_mutex_unlock(&key_lock)) != 0)
326                 return error;
327
328         return 0;
329 }
330
331
332 /**
333  * fosa_thread_set_specific_data()
334  *
335  * Set thread-specific data
336  *
337  * For the thread identified by tid, the thread-specifid data field
338  * identified by key will be set to the value specified by value
339  * 
340  * In this implementation, according to POSIX, the accessed data field
341  * is the one of the calling thread, not the one specified via tid.
342  *
343  * Returns 0 if successful; otherwise, an error code is returned
344  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
345  **/
346  int fosa_thread_set_specific_data(int key,
347                                    fosa_thread_id_t tid,
348                                    const void * value)
349 {
350         /* only POSIX threads can have specific data */
351         if (!__fosa_check_thread(&tid))
352                 return EINVAL;
353
354         return pthread_setspecific(key_list[key], value);
355 }
356
357 /**
358  * fosa_thread_get_specific_data()
359  *
360  * Get thread-specific data
361  *
362  * For the thread identified by tid, the thread-specifid data field
363  * identified by key will be copied to the variable pointed to by value
364  * 
365  * In this implementation, according to POSIX, the accessed data field
366  * is the one of the calling thread, not the one specified via tid.
367  *
368  * Returns 0 if successful; otherwise, an error code is returned
369  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
370  **/
371 int fosa_thread_get_specific_data(int key,
372                                   fosa_thread_id_t tid,
373                                   void ** value)
374 {
375         /* only POSIX threads can have specific data */
376         if (!__fosa_check_thread(&tid))
377                 return EINVAL;
378
379         if ((value = pthread_getspecific(key_list[key])) != NULL)
380                 return EINVAL;
381         else
382                 return 0;
383 }
384
385 /******************************************************************
386  * Thread scheduling
387  * 
388  * This implementation of FRSH assumes an underlying fixed priority
389  * scheduler with priorities in a range, with a minimum and a
390  * maximumm, a number of priority levels with at least 31
391  * priorities. A larger number implies a larger priority. In systems
392  * in which the underlying scheduler uses the opposite convention, a
393  * mapping is automatically provided by the OS adaptation layer.
394  *******************************************************************/
395
396 /**
397  * fosa_get_priority_max()
398  *
399  * Return the maximum priority value used in this implementation
400  **/
401 int fosa_get_priority_max()
402 {
403         return sched_get_priority_max(SCHED_RR);
404 }
405
406 /**
407  * fosa_get_priority_min()
408  *
409  * Return the minimum priority value used in this implementation
410  **/
411 int fosa_get_priority_min()
412 {
413         return sched_get_priority_min(SCHED_RR);
414 }
415
416 /**
417  * fosa_thread_attr_set_prio()
418  *
419  * Change the priority of a thread attributes object
420  *
421  * The priority of the thread attriutes object specified by attr is
422  * set to the value specified by prio. This function has no runtime
423  * effect on the priority, except when the attributes object is used
424  * to create a thread, when it will be created with the specified
425  * priority
426  * 
427  * Returns 0 if successful, or the following error code:
428  *    EINVAL: the specified priority value is not between the 
429  *            minimum and the maximum priorities defined in this
430  *            FRSH implementation
431  **/
432 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
433 {
434         int error;
435         struct sched_param param;
436
437         param.sched_priority = prio;
438         if ((error = pthread_attr_setschedpolicy(attr, SCHED_RR)) == 0)
439                 return error;
440
441         return pthread_attr_setschedparam(attr, &param);
442 }
443
444 /**
445  * fosa_thread_attr_get_prio()
446  *
447  * Get the priority from a thread attributes object
448  *
449  * This function sets the variable pointed to by prio to the
450  * priority stored in the thread attributes object attr.
451  * 
452  * Returns 0
453  **/
454 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
455 {
456         int error;
457         struct sched_param param;
458
459         if ((error = pthread_attr_getschedparam(attr, &param)) == 0)
460                 *prio = param.sched_priority;
461
462         return error;
463 }
464
465 /**
466  * fosa_thread_set_prio()
467  *
468  * Dynamically change the priority of a thread
469  *
470  * The priority of the thread identified by tid is
471  * set to the value specified by prio. 
472  * 
473  * Returns 0 if successful, or the following error code:
474  *    EINVAL: the specified priority value is not between the 
475  *            minimum and the maximum priorities defined in this
476  *            FRSH implementation
477  **/
478 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
479 {
480         struct sched_param param;
481
482         param.sched_priority = prio;
483         return sched_setscheduler(0, SCHED_RR, &param);
484 }
485
486 /**
487  * fosa_thread_get_prio()
488  *
489  * Dynamically get the priority of a thread
490  *
491  * This function sets the variable pointed to by prio to the
492  * priority of the thread identified by tid
493  * 
494  * Returns 0
495  **/
496 int fosa_thread_get_prio(fosa_thread_id_t tid, int *prio)
497 {
498         struct sched_param param;
499         int ret;
500
501         ret = sched_getparam(0, &param);
502         *prio = param.sched_priority;
503
504         return ret;
505 }
506
507 /*******************************************************************
508  * Signals
509  *
510  * Signals represent events that may be notified by the system, or
511  * sent explicitly by the application, and for which a thread may
512  * synchronously wait. Signals carry an associated piece of
513  * information (an integer or a pointer) and are queued until they are
514  * accepted.  Signals are identified by an integer signal number (of
515  * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
516  * FOSA_SIGNAL_MAX.  This range is required to have at least <tbd>
517  * values.
518  *******************************************************************/
519
520 /**
521  * fosa_set_accepted_signals()
522  *
523  * Establish the set of signals that may be synchronously accepted 
524  * by the calling thread
525  *
526  * The function uses the array of signal numbers specified by set,
527  * which must be of size equal to size
528  *
529  * Returns 0 if successful; otherwise it returns an error code:
530  *     EINVAL: the array contains one or more values which are not
531  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
532  *             is less than 0
533  *
534  * Alternatively, in case of error the implementation is allowed to
535  * notify it to the system console and then terminate the FRSH
536  * implementation and dependant applications
537  **/
538 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
539 {
540         int i, error;
541         fosa_thread_id_t self;
542         sigset_t sigset;
543         struct sigaction action;
544
545         if ((error = sigemptyset(&sigset)) != 0)
546                 return error;
547
548         action.sa_handler = SIG_DFL;
549         action.sa_mask = sigset;
550         action.sa_flags = SA_SIGINFO;
551         action.sa_sigaction = NULL;
552
553         for (i = 0; i < size; i++) {
554                 if ((error = sigaddset(&sigset, set[i])) != 0)
555                         return error;
556                 if ((error = sigaction(set[i], &action, NULL)) != 0)
557                         return error;
558         }
559
560         self = fosa_thread_self();
561         if (__fosa_check_thread(&self))
562                 return pthread_sigmask(SIG_BLOCK, &sigset, NULL);
563         else
564                 return sigprocmask(SIG_BLOCK, &sigset, NULL);
565 }
566
567 /**
568  * fosa_signal_queue()
569  *
570  * Queue a signal
571  *
572  * This function is used to explicitly send a signal with a specified
573  * value
574  * 
575  * The signal number specified by signal is sent together with the
576  * information specified by info, to the thread identified by
577  * receiver. In those implementations that do not support queueing a
578  * signal with information to a thread (such as POSIX), the signal may
579  * be sent to any thread that is waiting for this signal via
580  * fosa_signal_wait(). Portability can be ensured by having the receiver
581  * thread be the one who is waiting for the signal. 
582  *
583  * In this implementation, this limitation has been overcome by means
584  * of the Linux specific capability of sending a timer event directly
585  * to a specific thread. Thus, we program a fake timer to fire immediately
586  * and notify such event to the requested receiver thread.
587  *
588  * Returns 0 if successful; otherwise it returns an error code:
589  *     EINVAL: the signal specified by signal is not
590  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
591  *
592  *     EAGAIN: no resources are available to queue the signal; the
593  *             maximum number of queued signals has been reached, or a
594  *             systemwide resource limit has been exceeded
595  *
596  * Alternatively, in case of error the implementation is allowed to
597  * notify it to the system console and then terminate the FRSH
598  * implementation and dependant applications
599  **/
600 int fosa_signal_queue(fosa_signal_t signal,
601                       fosa_signal_info_t info,
602                       fosa_thread_id_t receiver)
603 {
604         int error;
605         timer_t fake_timer;
606         struct itimerspec fake_time;
607         struct sigevent fake_event;
608
609         timer_create(CLOCK_MONOTONIC, &fake_event, &fake_timer);
610
611         fake_time.it_value.tv_sec = fake_time.it_value.tv_nsec = 0;
612         fake_time.it_interval.tv_sec = fake_time.it_interval.tv_nsec = 0;
613         fake_event.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
614         fake_event.sigev_signo  = SIGRTMIN;
615         fake_event.sigev_value.sival_int = info.sival_int;
616         fake_event._sigev_un._tid = receiver.linux_tid;
617
618         error = timer_settime(fake_timer, TIMER_ABSTIME, &fake_time, NULL);
619         timer_delete(fake_timer);
620
621         return error;
622 }
623
624 /**
625  * fosa_signal_wait()
626  *
627  * Wait for a signal
628  * 
629  * The function waits for the arrival of one of the signals in the
630  * array of signal numbers specified by set, which must be of size
631  * equal to size. If there is a signal already queued, the function
632  * returns immediately. If there is no signal of the specified set
633  * queued, the calling thread is suspended until a signal from that
634  * set arrives. Upon return, if signal_received is not NULL the number
635  * of the signal received is stored in the variable pointed to by
636  * signal_received; and if info is not NULL the associated information
637  * is stored in the variable pointed to by info.
638  *
639  * Returns 0 if successful; otherwise it returns an error code:
640  *     EINVAL: the array contains one or more values which are not
641  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
642  *             is less than 0
643  *
644  * Alternatively, in case of error the implementation is allowed to
645  * notify it to the system console and then terminate the FRSH
646  * implementation and dependant applications
647  **/
648 int fosa_signal_wait(fosa_signal_t set[], int size,
649                      fosa_signal_t *signal_received,
650                      fosa_signal_info_t *info)
651 {
652         int i, error;
653         sigset_t sigset;
654         siginfo_t siginfo;
655
656         if ((error = sigemptyset(&sigset)) != 0)
657                 return error;
658
659         for (i = 0; i < size; i++)
660                 if ((error = sigaddset(&sigset,set[i])) != 0)
661                         return error;
662
663         if ((error = sigwaitinfo(&sigset, &siginfo)) != 0)
664                 return error;
665
666         if (info != NULL && signal_received != NULL)
667                 *signal_received = siginfo.si_signo;
668         if (info != NULL)
669                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
670
671         return 0;
672 }
673
674 /**
675  * fosa_signal_timedwait()
676  *
677  * Timed wait for a signal
678  * 
679  * This function behaves the same as fosa_signal_wait(), except that
680  * the suspension time is limited to the time interval specified in
681  * the timespec structure referenced by timeout.
682  * 
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
686  *             is less than 0, or timeout is invalid
687  *     EAGAIN: The timeout expired
688  *
689  * Alternatively, in case of error the implementation is allowed to
690  * notify it to the system console and then terminate the FRSH
691  * implementation and dependant applications
692  **/
693 int fosa_signal_timedwait(fosa_signal_t set[], int size,
694                           fosa_signal_t *signal_received,
695                           fosa_signal_info_t *info,
696                           const struct timespec *timeout)
697 {
698         int i, error;
699         sigset_t signalset;
700         siginfo_t siginfo;
701
702         if ((error = sigemptyset(&signalset)) != 0)
703                 return error;
704
705         for (i = 0; i < size; i++)
706                 if ((error = sigaddset(&signalset,set[i])) != 0)
707                         return error;
708
709         if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0)
710                 return error;
711
712         if (signal_received != NULL)
713                 *signal_received = siginfo.si_signo;
714         if (info != NULL)
715                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
716
717         return 0;
718 }
719