]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_aquosa/fosa_threads_and_signals.c
Final update to phase II API.
[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         //if ((error = pthread_mutexattr_destroy(&attr)) != 0)
92         //      return error;
93
94         return 0;
95 }
96
97 /*************************
98  * Thread identification
99  *************************/ 
100
101 /**
102  * fosa_thread_equal()
103  *
104  * Compare two thread identifiers to determine if they refer to the 
105  * same thread
106  **/
107 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
108 {
109         return t1.linux_pid == t2.linux_pid &&
110                t1.linux_tid == t2.linux_tid &&
111                pthread_equal(t1.pthread_id, t2.pthread_id);
112 }
113
114 /**
115  * fosa_thread_self()
116  *
117  * Return the thread id of the calling thread
118  **/
119 fosa_thread_id_t fosa_thread_self()
120 {
121         fosa_thread_id_t thread_self;
122         /** 
123          * NB. Remember:
124          *  fosa_thread_id_t => struct {
125          *                       pthread_t pthread_id;
126          *                       pid_t linux_pid;
127          *                       tid_t linux_tid;
128          * };
129          **/
130         thread_self.pthread_id = pthread_self();
131         thread_self.linux_pid = getpid();
132         thread_self.linux_tid = syscall(__NR_gettid);   /* gettid() */
133
134         return thread_self;
135 }
136
137 /*************************
138  * Thread attributes
139  *************************/
140
141 /**
142  * fosa_thread_attr_init()
143  *
144  * Initialize a thread attributes object
145  *
146  * This function initializes the object pointed to by attr to all 
147  * the default values defined by FRSH
148  *
149  * return 0 if successful; otherwise it returns
150  *   FOSA_ENOMEM: insufficient memory exists to initialize the thread 
151  *           attributes object
152  **/
153 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
154 {
155         fosa_thread_id_t self;
156
157         /* only POSIX threads have attributes */
158         self = fosa_thread_self();
159         if (self.linux_pid == self.linux_tid)
160                 return EINVAL;
161
162         return pthread_attr_init(attr);
163 }
164
165 /**
166  * fosa_thread_attr_destroy()
167  *
168  * Destroy a thread attributes object
169  *
170  * This function is used to destroy the thread attributes object,
171  * pointed to by attr, and deallocate any system resources allocated for it
172  * 
173  * Returns 0
174  **/
175 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
176 {
177         fosa_thread_id_t self;
178
179         /* only POSIX threads can have attributes */
180         self = fosa_thread_self();
181         if (self.linux_pid == self.linux_tid)
182                 return EINVAL;
183
184         return pthread_attr_destroy(attr);
185 }
186
187 /**
188  * fosa_thread_attr_set_stacksize()
189  *
190  * Set the thread minimum stack size in a thread attributes object
191  *
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
197  * 
198  * return 0 if successful, or the following error code:
199  *    FOSA_EINVAL: the specified stacksize  value is not supported in
200  *            this implementation
201  **/
202 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
203                                    size_t stacksize)
204 {
205         fosa_thread_id_t self;
206
207         /* only POSIX threads can set the size of the stack */
208         self = fosa_thread_self();
209         if (self.linux_pid == self.linux_tid)
210                 return EINVAL;
211
212         return pthread_attr_setstacksize(attr, stacksize);
213 }
214
215 /**
216  * fosa_thread_attr_get_stacksize()
217  *
218  * Get the thread minimum stack size from a thread attributes object
219  *
220  * This function sets the variable pointed to by stacksize to the
221  * minimum stack size stored in the thread attributes object attr.
222  * 
223  * return 0
224  **/
225 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
226                                    size_t *stacksize)
227 {
228         fosa_thread_id_t self;
229
230         /* only POSIX threads can set the size of the stack */
231         self = fosa_thread_self();
232         if (self.linux_pid == self.linux_tid)
233                 return EINVAL;
234
235         return pthread_attr_getstacksize(attr, stacksize);
236 }
237
238 /*************************
239  * Thread creation and termination
240  *************************/
241
242 /**
243  * fosa_thread_create()
244  *
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.
252  *
253  * Returns 0 if successful; otherwise it returs a code error:
254  *
255  *     EAGAIN: the system lacks the necessary resources to create a
256  *             new thread or the maximum number of threads has been
257  *             reached
258  *
259  *     EINVAL: the value specified by attr is invalid (for instance,
260  *              it has not been correctly initialized)
261  *
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
265  **/
266 int fosa_thread_create(fosa_thread_id_t *tid,
267                        const fosa_thread_attr_t *attr,
268                        fosa_thread_code_t code,
269                        void *arg)
270 {
271         return pthread_create(&tid->pthread_id, attr, code, arg);
272 }
273
274 /**
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
278  **/
279
280 /**************************************************
281  * Thread-specific data
282  *  (extended with access from a different thread)
283  *
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  **************************************************/ 
289
290 /**
291  * fosa_key_create()
292  *
293  * Create a new key for thread specific data.
294  *
295  * Prior to setting data in a key, we need ask the system to create
296  * one for us.
297  *
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 
301  *               create the key.
302  **/
303 int fosa_key_create(int *key)
304 {
305         int i, error = 0;
306         bool found = false;
307         fosa_thread_id_t self;
308
309         /* only POSIX threads can have specific data */
310         self = fosa_thread_self();
311         if (self.linux_pid == self.linux_tid)
312                 return EINVAL;
313
314         if ((error = pthread_mutex_lock(&key_lock)) != 0)
315                 return error;
316
317         /* find an unused key */
318         for (i = 0; i < FOSA_MAX_KEYS; i++) {
319                 if (!key_in_use[i]) {
320                         *key = i;
321                         key_in_use[i] = true;
322                         error = pthread_key_create(&(key_list[i]), NULL);
323                         found = true;
324                         break;
325                 }
326         }
327
328         if ((error = pthread_mutex_unlock(&key_lock))!= 0)
329                 return error;
330
331         return (!found ? FOSA_EINVAL : error);
332 }
333
334 /**
335  * fosa_key_destroy()
336  *
337  * Destroy a key
338  *
339  * This destroys the key and isables its use in the system
340  *
341  * return 0 if successful
342  *   FOSA_EINVAL The key is not initialised or is not in FOSA key range.
343  **/
344 int fosa_key_destroy(int key)
345 {
346         int error;
347         fosa_thread_id_t self;
348
349         /* only POSIX threads can have specific data */
350         self = fosa_thread_self();
351         if (self.linux_pid == self.linux_tid)
352                 return EINVAL;
353
354         if ((error = pthread_mutex_lock(&key_lock)) != 0)
355                 return error;
356
357         if ((error = pthread_key_delete(key_list[key])) != 0)
358                 key_in_use[key]=false;
359
360         if ((error = pthread_mutex_unlock(&key_lock)) != 0)
361                 return error;
362
363         return 0;
364 }
365
366
367 /**
368  * fosa_thread_set_specific_data()
369  *
370  * Set thread-specific data
371  *
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
374  * 
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.
377  *
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
380  **/
381  int fosa_thread_set_specific_data(int key,
382                                    fosa_thread_id_t tid,
383                                    const void * value)
384 {
385         fosa_thread_id_t self;
386
387         /* only POSIX threads can have specific data */
388         self = fosa_thread_self();
389         if (self.linux_pid == self.linux_tid)
390                 return EINVAL;
391
392         return pthread_setspecific(key_list[key], value);
393 }
394
395 /**
396  * fosa_thread_get_specific_data()
397  *
398  * Get thread-specific data
399  *
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
402  * 
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.
405  *
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
408  **/
409 int fosa_thread_get_specific_data(int key,
410                                   fosa_thread_id_t tid,
411                                   void ** value)
412 {
413         fosa_thread_id_t self;
414
415         /* only POSIX threads can have specific data */
416         self = fosa_thread_self();
417         if (self.linux_pid == self.linux_tid)
418                 return EINVAL;
419
420         if ((value = pthread_getspecific(key_list[key])) != NULL)
421                 return EINVAL;
422         else
423                 return 0;
424 }
425
426 /******************************************************************
427  * Thread scheduling
428  * 
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  *******************************************************************/
436
437 /**
438  * fosa_get_priority_max()
439  *
440  * Return the maximum priority value used in this implementation
441  **/
442 int fosa_get_priority_max()
443 {
444         return sched_get_priority_max(SCHED_FIFO);
445 }
446
447 /**
448  * fosa_get_priority_min()
449  *
450  * Return the minimum priority value used in this implementation
451  **/
452 int fosa_get_priority_min()
453 {
454         return sched_get_priority_min(SCHED_FIFO);
455 }
456
457 /**
458  * fosa_thread_attr_set_prio()
459  *
460  * Change the priority of a thread attributes object
461  *
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
466  * priority
467  * 
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
472  **/
473 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
474 {
475         fosa_thread_id_t self;
476         struct sched_param param;
477
478         /* normal UNIX processes have no attributes */
479         self = fosa_thread_self();
480         if (self.linux_pid == self.linux_tid)
481                 return EINVAL;
482         
483         param.sched_priority = prio;
484
485         return pthread_attr_setschedparam(attr, &param);
486 }
487
488 /**
489  * fosa_thread_attr_get_prio()
490  *
491  * Get the priority from a thread attributes object
492  *
493  * This function sets the variable pointed to by prio to the
494  * priority stored in the thread attributes object attr.
495  * 
496  * Returns 0
497  **/
498 int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio)
499 {
500         int error;
501         fosa_thread_id_t self;
502         struct sched_param param;
503
504         /* normal UNIX processes have no attributes */
505         self = fosa_thread_self();
506         if (self.linux_pid == self.linux_tid)
507                 return EINVAL;
508
509         if ((error = pthread_attr_getschedparam(attr, &param)) == 0)
510                 *prio = param.sched_priority;
511
512         return error;
513 }
514
515 /**
516  * fosa_thread_set_prio()
517  *
518  * Dynamically change the priority of a thread
519  *
520  * The priority of the thread identified by tid is
521  * set to the value specified by prio. 
522  * 
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
527  **/
528 int fosa_thread_set_prio(fosa_thread_id_t tid, int prio)
529 {
530         struct sched_param param;
531
532         param.sched_priority=prio;
533
534         return sched_setscheduler(0, SCHED_RR, &param);
535 }
536
537 /**
538  * fosa_thread_get_prio()
539  *
540  * Dynamically get the priority of a thread
541  *
542  * This function sets the variable pointed to by prio to the
543  * priority of the thread identified by tid
544  * 
545  * Returns 0
546  **/
547 int fosa_thread_get_prio(fosa_thread_id_t tid, int *prio)
548 {
549         struct sched_param param;
550         int error;
551
552         error = sched_getparam(0, &param);
553         *prio = param.sched_priority;
554
555         return error;
556 }
557
558 /*******************************************************************
559  * Signals
560  *
561  * Signals represent events that may be notified by the system, or
562  * sent explicitly by the application, and for which a thread may
563  * synchronously wait. Signals carry an associated piece of
564  * information (an integer or a pointer) and are queued until they are
565  * accepted.  Signals are identified by an integer signal number (of
566  * the type fosa_signal_t) in the range FOSA_SIGNAL_MIN,
567  * FOSA_SIGNAL_MAX.  This range is required to have at least <tbd>
568  * values.
569  *******************************************************************/
570
571 /**
572  * fosa_set_accepted_signals()
573  *
574  * Establish the set of signals that may be synchronously accepted 
575  * by the calling thread
576  *
577  * The function uses the array of signal numbers specified by set,
578  * which must be of size equal to size
579  *
580  * Returns 0 if successful; otherwise it returns an error code:
581  *     EINVAL: the array contains one or more values which are not
582  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
583  *             is less than 0
584  **/
585 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
586 {
587         int i, error;
588         fosa_thread_id_t self;
589         sigset_t sigset;
590         struct sigaction action;
591
592         if ((error = sigemptyset(&sigset)) != 0)
593                 return error;
594
595         /* real-time signal (can be queued) */
596         action.sa_handler = SIG_DFL;
597         action.sa_mask = sigset;
598         action.sa_flags = SA_SIGINFO;
599         action.sa_sigaction = NULL;
600
601         for (i = 0; i < size; i++) {
602                 if ((error = sigaddset(&sigset, set[i])) != 0)
603                         return error;
604                 if ((error = sigaction(set[i], &action, NULL)) != 0)
605                         return error;
606         }
607
608         self = fosa_thread_self();
609         if (self.linux_pid == self.linux_tid)
610                 return pthread_sigmask(SIG_BLOCK, &sigset, NULL);
611         else
612                 return sigprocmask(SIG_BLOCK, &sigset, NULL);
613 }
614
615 /**
616  * fosa_signal_queue()
617  *
618  * Queue a signal
619  *
620  * This function is used to explicitly send a signal with a specified
621  * value
622  * 
623  * The signal number specified by signal is sent together with the
624  * information specified by info, to the thread identified by
625  * receiver.
626  * 
627  * Note that, in this implementation, the signal is sent to any thread
628  * waiting for it (maybe via fosa_signal_wait()).
629  * If needed ensure the receiver is the only one who is waiting for the
630  * signal (e.g., by using different signal numbers for each thread). 
631  *
632  * Returns 0 if successful; otherwise it returns an error code:
633  *     EINVAL: the signal specified by signal is not
634  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
635  *
636  *     EAGAIN: no resources are available to queue the signal; the
637  *             maximum number of queued signals has been reached, or a
638  *             systemwide resource limit has been exceeded
639  **/
640 int fosa_signal_queue(fosa_signal_t signal,
641                       fosa_signal_info_t info,
642                       fosa_thread_id_t receiver)
643 {
644         /* Note: signal sent to a "whole" process */
645         return sigqueue(receiver.linux_pid, signal, *((union sigval*) &info));
646 }
647
648 /**
649  * fosa_signal_wait()
650  *
651  * Wait for a signal
652  * 
653  * The function waits for the arrival of one of the signals in the
654  * array of signal numbers specified by set, which must be of size
655  * equal to size. If there is a signal already queued, the function
656  * returns immediately. If there is no signal of the specified set
657  * queued, the calling thread is suspended until a signal from that
658  * set arrives. Upon return, if signal_received is not NULL the number
659  * of the signal received is stored in the variable pointed to by
660  * signal_received; and if info is not NULL the associated information
661  * is stored in the variable pointed to by info.
662  *
663  * Returns 0 if successful; otherwise it returns an error code:
664  *     EINVAL: the array contains one or more values which are not
665  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
666  *             is less than 0
667  **/
668 int fosa_signal_wait(fosa_signal_t set[], int size,
669                      fosa_signal_t *signal_received,
670                      fosa_signal_info_t *info)
671 {
672         int i, error;
673         sigset_t sigset;
674         siginfo_t siginfo;
675
676         if ((error = sigemptyset(&sigset)) != 0)
677                 return error;
678
679         for (i = 0; i < size; i++)
680                 if ((error = sigaddset(&sigset,set[i])) != 0)
681                         return error;
682
683         if ((error = sigwaitinfo(&sigset, &siginfo)) != 0)
684                 return error;
685
686         if (signal_received != NULL)
687                 *signal_received = siginfo.si_signo;
688         if (info != NULL)
689                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
690
691         return 0;
692 }
693
694 /**
695  * fosa_signal_timedwait()
696  *
697  * Timed wait for a signal
698  * 
699  * This function behaves the same as fosa_signal_wait(), except that
700  * the suspension time is limited to the time interval specified in
701  * the timespec structure referenced by timeout.
702  * 
703  * Returns 0 if successful; otherwise it returns an error code:
704  *     EINVAL: the array contains one or more values which are not
705  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
706  *             is less than 0, or timeout is invalid
707  *     EAGAIN: The timeout expired
708  **/
709 int fosa_signal_timedwait(fosa_signal_t set[], int size,
710                           fosa_signal_t *signal_received,
711                           fosa_signal_info_t *info,
712                           const struct timespec *timeout)
713 {
714         int i, error;
715         sigset_t signalset;
716         siginfo_t siginfo;
717
718         if ((error = sigemptyset(&signalset)) != 0)
719                 return error;
720
721         for (i = 0; i < size; i++)
722                 if ((error = sigaddset(&signalset,set[i])) != 0)
723                         return error;
724
725         if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0)
726                 return error;
727
728         if (signal_received != NULL)
729                 *signal_received = siginfo.si_signo;
730         if (info != NULL)
731                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
732
733         return 0;
734 }
735