]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_aquosa/fosa_threads_and_signals.c
Keep the FOSA implementation for the AQuoSA platform in touch
[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_threads_and_signals.h"
61 #include "fosa_configuration_parameters.h"
62
63 /*************************
64  * Storage of thread-specific keys
65  *************************/
66
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;
70
71
72 /* Initialize the keys data structure */
73 int init_keys()
74 {
75         int i, error;
76         pthread_mutexattr_t attr;
77
78         for(i = 0; i < FOSA_MAX_KEYS; i++)
79                 key_in_use[i] = false;
80
81         if ((error = pthread_mutexattr_init(&attr)) != 0)
82                 return error;
83
84         if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0)
85                 return error;
86
87         if ((error = pthread_mutex_init(&key_lock,&attr)) != 0)
88                 return error;
89
90         //if ((error = pthread_mutexattr_destroy(&attr)) != 0)
91         //      return error;
92
93         return 0;
94 }
95
96 /*************************
97  * Thread identification
98  *************************/ 
99
100 /**
101  * fosa_thread_equal()
102  *
103  * Compare two thread identifiers to determine if they refer to the 
104  * same thread
105  **/
106 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
107 {
108         return t1.linux_pid == t2.linux_pid &&
109                t1.linux_tid == t2.linux_tid &&
110                pthread_equal(t1.pthread_id, t2.pthread_id);
111 }
112
113 /**
114  * fosa_thread_self()
115  *
116  * Return the thread id of the calling thread
117  **/
118 fosa_thread_id_t fosa_thread_self()
119 {
120         fosa_thread_id_t thread_self;
121         /** 
122          * NB. Remember:
123          *  fosa_thread_id_t => struct {
124          *                       pthread_t pthread_id;
125          *                       pid_t linux_pid;
126          *                       tid_t linux_tid;
127          * };
128          **/
129         thread_self.pthread_id = pthread_self();
130         thread_self.linux_pid = getpid();
131         thread_self.linux_tid = syscall(__NR_gettid);   /* gettid() */
132
133         return thread_self;
134 }
135
136 /*************************
137  * Thread attributes
138  *************************/
139
140 /**
141  * fosa_thread_attr_init()
142  *
143  * Initialize a thread attributes object
144  *
145  * This function initializes the object pointed to by attr to all 
146  * the default values defined by FRSH
147  *
148  * return 0 if successful; otherwise it returns
149  *   FOSA_ENOMEM: insufficient memory exists to initialize the thread 
150  *           attributes object
151  **/
152 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
153 {
154         fosa_thread_id_t self;
155
156         /* only POSIX threads have attributes */
157         self = fosa_thread_self();
158         if (self.linux_pid == self.linux_tid)
159                 return EINVAL;
160
161         return pthread_attr_init(attr);
162 }
163
164 /**
165  * fosa_thread_attr_destroy()
166  *
167  * Destroy a thread attributes object
168  *
169  * This function is used to destroy the thread attributes object,
170  * pointed to by attr, and deallocate any system resources allocated for it
171  * 
172  * Returns 0
173  */
174 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
175 {
176         fosa_thread_id_t self;
177
178         /* only POSIX threads can have attributes */
179         self = fosa_thread_self();
180         if (self.linux_pid == self.linux_tid)
181                 return EINVAL;
182
183         return pthread_attr_destroy(attr);
184 }
185
186 /**
187  * fosa_thread_attr_set_stacksize()
188  *
189  * Set the thread minimum stack size in a thread attributes object
190  *
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
196  * 
197  * return 0 if successful, or the following error code:
198  *    FOSA_EINVAL: the specified stacksize  value is not supported in
199  *            this implementation
200  */
201 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
202                                    size_t stacksize)
203 {
204         fosa_thread_id_t self;
205
206         /* only POSIX threads can set the size of the stack */
207         self = fosa_thread_self();
208         if (self.linux_pid == self.linux_tid)
209                 return EINVAL;
210
211         return pthread_attr_setstacksize(attr, stacksize);
212 }
213
214 /**
215  * fosa_thread_attr_get_stacksize()
216  *
217  * Get the thread minimum stack size from a thread attributes object
218  *
219  * This function sets the variable pointed to by stacksize to the
220  * minimum stack size stored in the thread attributes object attr.
221  * 
222  * return 0
223  */
224 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
225                                    size_t *stacksize)
226 {
227         fosa_thread_id_t self;
228
229         /* only POSIX threads can set the size of the stack */
230         self = fosa_thread_self();
231         if (self.linux_pid == self.linux_tid)
232                 return EINVAL;
233
234         return pthread_attr_getstacksize(attr, stacksize);
235 }
236
237 /*************************
238  * Thread creation and termination
239  *************************/
240
241 /**
242  * fosa_thread_create()
243  *
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.
251  *
252  * Returns 0 if successful; otherwise it returs a code error:
253  *
254  *     EAGAIN: the system lacks the necessary resources to create a
255  *             new thread or the maximum number of threads has been
256  *             reached
257  *
258  *     EINVAL: the value specified by attr is invalid (for instance,
259  *              it has not been correctly initialized)
260  *
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
264  **/
265 int fosa_thread_create(fosa_thread_id_t *tid,
266                        const fosa_thread_attr_t *attr,
267                        fosa_thread_code_t code,
268                        void *arg)
269 {
270         return pthread_create(&tid->pthread_id, attr, code, arg);
271 }
272
273 /**
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
277  **/
278
279 /**************************************************
280  * Thread-specific data
281  *  (extended with access from a different thread)
282  *
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  **************************************************/ 
288
289 /**
290  * fosa_key_create()
291  *
292  * Create a new key for thread specific data.
293  *
294  * Prior to setting data in a key, we need ask the system to create
295  * one for us.
296  *
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 
300  *               create the key.
301  **/
302 int fosa_key_create(int *key)
303 {
304         int i, error = 0;
305         bool found = false;
306         fosa_thread_id_t self;
307
308         /* only POSIX threads can have specific data */
309         self = fosa_thread_self();
310         if (self.linux_pid == self.linux_tid)
311                 return EINVAL;
312
313         if ((error = pthread_mutex_lock(&key_lock)) != 0)
314                 return error;
315
316         /* find an unused key */
317         for (i = 0; i < FOSA_MAX_KEYS; i++) {
318                 if (!key_in_use[i]) {
319                         *key = i;
320                         key_in_use[i] = true;
321                         error = pthread_key_create(&(key_list[i]), NULL);
322                         found = true;
323                         break;
324                 }
325         }
326
327         if ((error = pthread_mutex_unlock(&key_lock))!= 0)
328                 return error;
329
330         return (!found ? FOSA_EINVAL : error);
331 }
332
333 /**
334  * fosa_key_destroy()
335  *
336  * Destroy a key
337  *
338  * This destroys the key and isables its use in the system
339  *
340  * return 0 if successful
341  *   FOSA_EINVAL The key is not initialised or is not in FOSA key range.
342  **/
343 int fosa_key_destroy(int key)
344 {
345         int error;
346         fosa_thread_id_t self;
347
348         /* only POSIX threads can have specific data */
349         self = fosa_thread_self();
350         if (self.linux_pid == self.linux_tid)
351                 return EINVAL;
352
353         if ((error = pthread_mutex_lock(&key_lock)) != 0)
354                 return error;
355
356         if ((error = pthread_key_delete(key_list[key])) != 0)
357                 key_in_use[key]=false;
358
359         if ((error = pthread_mutex_unlock(&key_lock)) != 0)
360                 return error;
361
362         return 0;
363 }
364
365
366 /**
367  * fosa_thread_set_specific_data()
368  *
369  * Set thread-specific data
370  *
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
373  * 
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.
376  *
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
379  **/
380  int fosa_thread_set_specific_data(int key,
381                                    fosa_thread_id_t tid,
382                                    const void * value)
383 {
384         fosa_thread_id_t self;
385
386         /* only POSIX threads can have specific data */
387         self = fosa_thread_self();
388         if (self.linux_pid == self.linux_tid)
389                 return EINVAL;
390
391         return pthread_setspecific(key_list[key], value);
392 }
393
394 /**
395  * fosa_thread_get_specific_data()
396  *
397  * Get thread-specific data
398  *
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
401  * 
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.
404  *
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
407  **/
408 int fosa_thread_get_specific_data(int key,
409                                   fosa_thread_id_t tid,
410                                   void ** value)
411 {
412         fosa_thread_id_t self;
413
414         /* only POSIX threads can have specific data */
415         self = fosa_thread_self();
416         if (self.linux_pid == self.linux_tid)
417                 return EINVAL;
418
419         if ((value = pthread_getspecific(key_list[key])) != NULL)
420                 return EINVAL;
421         else
422                 return 0;
423 }
424
425 /******************************************************************
426  * Thread scheduling
427  * 
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  *******************************************************************/
435
436 /**
437  * fosa_get_priority_max()
438  *
439  * Return the maximum priority value used in this implementation
440  **/
441 int fosa_get_priority_max()
442 {
443         return sched_get_priority_max(SCHED_FIFO);
444 }
445
446 /**
447  * fosa_get_priority_min()
448  *
449  * Return the minimum priority value used in this implementation
450  **/
451 int fosa_get_priority_min()
452 {
453         return sched_get_priority_min(SCHED_FIFO);
454 }
455
456 /**
457  * fosa_thread_attr_set_prio()
458  *
459  * Change the priority of a thread attributes object
460  *
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
465  * priority
466  * 
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
471  **/
472 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
473 {
474         fosa_thread_id_t self;
475         struct sched_param param;
476
477         /* normal UNIX processes have no attributes */
478         self = fosa_thread_self();
479         if (self.linux_pid == self.linux_tid)
480                 return EINVAL;
481         
482         param.sched_priority = prio;
483
484         return pthread_attr_setschedparam(attr, &param);
485 }
486
487 /**
488  * fosa_thread_attr_get_prio()
489  *
490  * Get the priority from a thread attributes object
491  *
492  * This function sets the variable pointed to by prio to the
493  * priority stored in the thread attributes object attr.
494  * 
495  * Returns 0
496  **/
497 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
498 {
499         int error;
500         fosa_thread_id_t self;
501         struct sched_param param;
502
503         /* normal UNIX processes have no attributes */
504         self = fosa_thread_self();
505         if (self.linux_pid == self.linux_tid)
506                 return EINVAL;
507
508         if ((error = pthread_attr_getschedparam(attr, &param)) == 0)
509                 *prio = param.sched_priority;
510
511         return error;
512 }
513
514 /**
515  * fosa_thread_set_prio()
516  *
517  * Dynamically change the priority of a thread
518  *
519  * The priority of the thread identified by tid is
520  * set to the value specified by prio. 
521  * 
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
526  **/
527 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
528 {
529         struct sched_param param;
530         int error;
531
532         param.sched_priority=prio;
533         if (tid.linux_pid == tid.linux_tid)
534                 error = sched_setscheduler(tid.linux_pid,
535                                            SCHED_RR,
536                                            &param);
537         else
538                 error = pthread_setschedparam(tid.pthread_id,
539                                                SCHED_RR,
540                                                &param);
541
542         return error;
543 }
544
545 /**
546  * fosa_thread_get_prio()
547  *
548  * Dynamically get the priority of a thread
549  *
550  * This function sets the variable pointed to by prio to the
551  * priority of the thread identified by tid
552  * 
553  * Returns 0
554  **/
555 int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio)
556 {
557         struct sched_param param;
558         int policy, error;
559
560         if (tid.linux_pid == tid.linux_tid)
561                 error = sched_getparam(tid.linux_pid, &param);
562         else
563                 error = pthread_getschedparam(tid.pthread_id,
564                                               &policy,
565                                               &param);
566
567         *prio = param.sched_priority;
568
569         return error;
570 }
571
572 /*******************************************************************
573  * Signals
574  *
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>
582  * values.
583  *******************************************************************/
584
585 /**
586  * fosa_set_accepted_signals()
587  *
588  * Establish the set of signals that may be synchronously accepted 
589  * by the calling thread
590  *
591  * The function uses the array of signal numbers specified by set,
592  * which must be of size equal to size
593  *
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
597  *             is less than 0
598  **/
599 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
600 {
601         int i, error;
602         fosa_thread_id_t self;
603         sigset_t sigset;
604         struct sigaction action;
605
606         if ((error = sigemptyset(&sigset)) != 0)
607                 return error;
608
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;
614
615         for (i = 0; i < size; i++) {
616                 if ((error = sigaddset(&sigset, set[i])) != 0)
617                         return error;
618                 if ((error = sigaction(set[i], &action, NULL)) != 0)
619                         return error;
620         }
621
622         self = fosa_thread_self();
623         if (self.linux_pid == self.linux_tid)
624                 return pthread_sigmask(SIG_BLOCK, &sigset, NULL);
625         else
626                 return sigprocmask(SIG_BLOCK, &sigset, NULL);
627 }
628
629 /**
630  * fosa_signal_queue()
631  *
632  * Queue a signal
633  *
634  * This function is used to explicitly send a signal with a specified
635  * value
636  * 
637  * The signal number specified by signal is sent together with the
638  * information specified by info, to the thread identified by
639  * receiver.
640  * 
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). 
645  *
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
649  *
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
653  **/
654 int fosa_signal_queue(fosa_signal_t signal,
655                       fosa_signal_info_t info,
656                       fosa_thread_id_t receiver)
657 {
658         /* Note: signal sent to a "whole" process */
659         return sigqueue(receiver.linux_pid, signal, *((union sigval*) &info));
660 }
661
662 /**
663  * fosa_signal_wait()
664  *
665  * Wait for a signal
666  * 
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.
676  *
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
680  *             is less than 0
681  **/
682 int fosa_signal_wait(fosa_signal_t set[], int size,
683                      fosa_signal_t *signal_received,
684                      fosa_signal_info_t *info)
685 {
686         int i, error;
687         sigset_t sigset;
688         siginfo_t siginfo;
689
690         if ((error = sigemptyset(&sigset)) != 0)
691                 return error;
692
693         for (i = 0; i < size; i++)
694                 if ((error = sigaddset(&sigset,set[i])) != 0)
695                         return error;
696
697         if ((error = sigwaitinfo(&sigset, &siginfo)) != 0)
698                 return error;
699
700         if (signal_received != NULL)
701                 *signal_received = siginfo.si_signo;
702         if (info != NULL)
703                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
704
705         return 0;
706 }
707
708 /**
709  * fosa_signal_timedwait()
710  *
711  * Timed wait for a signal
712  * 
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.
716  * 
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
722  **/
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)
727 {
728         int i, error;
729         sigset_t signalset;
730         siginfo_t siginfo;
731
732         if ((error = sigemptyset(&signalset)) != 0)
733                 return error;
734
735         for (i = 0; i < size; i++)
736                 if ((error = sigaddset(&signalset,set[i])) != 0)
737                         return error;
738
739         if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0)
740                 return error;
741
742         if (signal_received != NULL)
743                 *signal_received = siginfo.si_signo;
744         if (info != NULL)
745                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
746
747         return 0;
748 }