]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_marte/fosa_threads_and_signals.c
5a7bd976a749f8e18c9748d0816569b2cd7cd93e
[frescor/fosa.git] / src_marte / 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 // -----------------------------------------------------------------------
41 //fosa_threads_and_signals.c
42 //==============================================
43 //  ********  ******    ********  **********
44 //  **///// /**    **  **//////  /**     /**
45 //  **      /**    ** /**        /**     /**
46 //  ******* /**    ** /********* /**********
47 //  **////  /**    ** ////////** /**//////**
48 //  **      /**    **        /** /**     /**
49 //  **      /**    **  ********  /**     /**
50 //  //       /******/  ////////   //      // 
51 //
52 // FOSA(Frescor Operating System Adaptation layer)
53 //================================================
54
55 #include "fosa_threads_and_signals.h"
56 #include "fosa_configuration_parameters.h"
57
58 #include <pthread.h>
59 #include <stdio.h>
60 #include <sched.h>
61
62 #include <misc/error_checks.h>
63
64 /**
65  * @defgroup threadandsignals Thread and Signals
66  * @ingroup fosa
67  *
68  * This module defines the functions that manipulate frsh_threads and
69  * frsh_signals inside FRSH implementation.
70  *
71  * Applications can refer to FRSH threads but they cannot create them
72  * directly, instead they must use frsh_thread_create*() which in turn
73  * use fosa_thread_create().
74  *
75  * For signals, we assume that the OS provides a direct mapping
76  * for frsh_signal_t and frsh_signal_info_t in the native interface.
77  *
78  * @{
79  **/
80
81 //////////////////////////////////////////////////////////////////
82 // Storage of thread-specific keys
83 //   - key_list is an array containing the keys
84 //   - key_in_use is an array of booleans 
85 //   - key_lock is a mutex that locks the data structure 
86 //        while creating a new key
87 //   - keys_initialized indicates whether the key_in_use array and 
88 //        the key_lock mutex are initialized or not; it is declared
89 //        volatile as it may be accessed concurrently
90 //////////////////////////////////////////////////////////////////
91
92 static pthread_key_t key_list[FOSA_MAX_KEYS];
93 static bool key_in_use[FOSA_MAX_KEYS];
94 static pthread_once_t keys_initialized=PTHREAD_ONCE_INIT;
95 static pthread_mutex_t key_lock;
96
97
98 // Initialize the keys data structure
99 // This function should be called from pthread_once() to ensure
100 // one single initialization
101
102 void init_keys() {
103   pthread_mutexattr_t attr;
104   int i;
105
106   // initialize the key_in_use array and the mutex
107   for(i=0; i<FOSA_MAX_KEYS;i++) {
108     key_in_use[i]=false;
109   }
110   // Initialize the mutex
111   CHK(pthread_mutexattr_init(&attr));
112   // we use the priority inheritance protocol because we don't know which
113   // tasks will be using the mutex
114   CHK(pthread_mutexattr_setprotocol(&attr,PTHREAD_PRIO_INHERIT));
115   CHK(pthread_mutex_init(&key_lock,&attr));
116   CHK(pthread_mutexattr_destroy(&attr));
117 }
118
119 /*************************
120  * Thread identification
121  *************************/ 
122
123 /**
124  * fosa_thread_equal()
125  *
126  * Compare two thread identifiers to determine if they refer to the 
127  * same thread
128  **/
129 bool fosa_thread_equal(frsh_thread_id_t t1, frsh_thread_id_t t2)
130 {
131   return pthread_equal(t1,t2);
132 }
133
134
135 /**
136  * fosa_thread_self()
137  *
138  * Return the thread id of the calling thread
139  **/
140 frsh_thread_id_t fosa_thread_self()
141 {
142   return pthread_self();
143 }
144
145
146 /*************************
147  * Thread creation and termination
148  *************************/ 
149
150 /**
151  * fosa_thread_create()
152  *
153  * This function creates a new thread using the attributes specified
154  * in attr. If attr is NULL, default attributes are used. The new
155  * thread starts running immediately, executing the function specified
156  * by code, with an argument equal to arg. Upon successful return, the
157  * variable pointed to by tid will contain the identifier of the newly
158  * created thread. The set of signals that may be synchronously
159  * accepted is inherited from the parent thread.
160  *
161  * Returns 0 if successful; otherwise it returs a code error:
162  *
163  *     EAGAIN: the system lacks the necessary resources to create a
164  *             new thread or the maximum number of threads has been
165  *             reached
166  *
167  *     EINVAL: the value specified by attr is invalid (for instance,
168  *              it has not been correctly initialized)
169  *
170  *     EREJECT: the cretion of the thread was rejected by the frsh scheduler
171  *               possibly because of incorrect attributes, or because the 
172  *               requested minimum capacity cannot be guaranteed
173  *
174  **/
175  int fosa_thread_create
176     (frsh_thread_id_t *tid, const frsh_thread_attr_t *attr, 
177      frsh_thread_code_t code, void * arg)
178 {
179   return pthread_create(tid,attr,code,arg);
180 }
181
182
183 /**
184  * Note: no thread termination primitive is provided. The termination
185  * of a thread will be notified by the system to the FRSH scheduler
186  * through the scheduler API
187  **/
188
189
190 /**************************************************
191  * Thread-specific data
192  *  (extended with access from a different thread)
193  *
194  * Several data items (pointers) may be associated with each thread
195  * Each item is identified through a key, an integer value between 0
196  * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
197  * deallocating the memory area pointed to by the pointer
198  **************************************************/ 
199
200 /**
201  * fosa_key_create()
202  *
203  * Create a new key for thread specific data.
204  *
205  * Prior to setting data in a key, we need ask the system to create
206  * one for us.
207  *
208  * @return 0 if successful \n
209  *   FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
210  *   FOSA_ENOMEM If there are no enough memory resources to 
211  *               create the key.
212  **/
213 int fosa_key_create(int *key)
214 {
215   int i,ret_value;
216   bool found=false;
217
218   // initialize the keys data structure if needed
219   CHK(pthread_once(&keys_initialized, init_keys));
220
221   // lock the mutex
222   CHK(pthread_mutex_lock(&key_lock));
223
224   // find an unused key
225   for(i=0; i<FOSA_MAX_KEYS;i++) {
226     if (!key_in_use[i]) {
227       *key=i;
228       key_in_use[i]=true;
229       ret_value=pthread_key_create(&(key_list[i]),NULL);
230       found=true;
231       break;
232     }
233   }
234   // unlock the mutex before returning
235   CHK(pthread_mutex_unlock(&key_lock));
236   if (!found) {
237     // all keys are in use; max keys reached
238     ret_value=FOSA_EINVAL;
239   }
240   return ret_value;
241 }
242
243 /**
244  * fosa_key_destroy()
245  *
246  * Destroy a key
247  *
248  * This destroys the key and isables its use in the system
249  *
250  * @return 0 if successful \n
251  *   FOSA_EINVAL The key is not initialised or is not in FOSA key range.
252  **/
253 int fosa_key_destroy(int key)
254 {
255   int ret_value;
256
257   // lock the mutex
258   CHK(pthread_mutex_lock(&key_lock));
259
260   // destroy the key and mark it as available
261   ret_value=pthread_key_delete(key_list[key]);
262   if (ret_value==0) {
263     key_in_use[key]=false;
264   }
265
266   // unlock the mutex before returning
267   CHK(pthread_mutex_unlock(&key_lock));
268   return ret_value;
269 }
270
271
272 /**
273  * fosa_thread_set_specific_data()
274  *
275  * Set thread-specific data
276  *
277  * For the thread identified by tid, the thread-specifid data field
278  * identified by key will be set to the value specified by value
279  *
280  * Returns 0 if successful; otherwise, an error code is returned
281  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
282  *
283  * Alternatively, in case of error the implementation is allowed to
284  * notify it to the system console and then terminate the FRSH
285  * implementation and dependant applications
286  **/
287  int fosa_thread_set_specific_data
288        (int key, frsh_thread_id_t tid, const void * value)
289 {
290   return pthread_setspecific_for(key_list[key],tid,value);
291 }
292
293 /**
294  * fosa_thread_get_specific_data()
295  *
296  * Get thread-specific data
297  *
298  * For the thread identified by tid, the thread-specifid data field
299  * identified by key will be copied to the variable pointed to by value
300  *
301  * Returns 0 if successful; otherwise, an error code is returned
302  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
303  *
304  * Alternatively, in case of error the implementation is allowed to
305  * notify it to the system console and then terminate the FRSH
306  * implementation and dependant applications
307  **/
308 int fosa_thread_get_specific_data(int key, frsh_thread_id_t tid, 
309                                   void ** value)
310 {
311   return pthread_getspecific_from(key_list[key],tid,value);
312 }
313
314
315 /******************************************************************
316  * Thread scheduling
317  * 
318  * This implementation of FRSH assumes an underlying fixed priority
319  * scheduler with priorities in a range, with a minimum and a
320  * maximumm, a number of priority levels with at least 31
321  * priorities. A larger number implies a larger priority. In systems
322  * in which the underlying scheduler uses the opposite convention, a
323  * mapping is automatically provided by the OS adaptation layer.
324  *******************************************************************/
325
326 /**
327  * fosa_get_priority_max()
328  *
329  * Return the maximum priority value used in this implementation
330  **/
331 int fosa_get_priority_max()
332 {
333   return sched_get_priority_max(SCHED_APP);
334 }
335
336 /**
337  * fosa_get_priority_min()
338  *
339  * Return the minimum priority value used in this implementation
340  **/
341 int fosa_get_priority_min()
342 {
343   return sched_get_priority_min(SCHED_APP);
344 }
345
346 /**
347  * fosa_thread_attr_set_prio()
348  *
349  * Change the priority of a thread attributes object
350  *
351  * The priority of the thread attriutes object specified by attr is
352  * set to the value specified by prio. This function has no runtime
353  * effect on the priority, except when the attributes object is used
354  * to create a thread, when it will be created with the specified
355  * priority
356  * 
357  * Returns 0 if successful, or the following error code:
358  *    EINVAL: the specified priority value is not between the 
359  *            minimum and the maximum priorities defined in this
360  *            FRSH implementation
361  * Alternatively, in case of error the implementation is allowed to
362  * notify it to the system console and then terminate the FRSH
363  * implementation and dependant applications
364  **/
365 int fosa_thread_attr_set_prio(frsh_thread_attr_t *attr, int prio)
366 {
367   struct sched_param param;
368
369   param.sched_priority=prio;
370   return pthread_attr_setschedparam(attr,&param);
371 }
372
373 /**
374  * fosa_thread_attr_get_prio()
375  *
376  * Get the priority from a thread attributes object
377  *
378  * This function sets the variable pointed to by prio to the
379  * priority stored in the thread attributes object attr.
380  * 
381  * Returns 0
382  **/
383 int fosa_thread_attr_get_prio
384           (const frsh_thread_attr_t *attr, int *prio)
385 {
386   struct sched_param param;
387   int ret_value;
388   
389   ret_value=pthread_attr_getschedparam(attr,&param);
390   if (ret_value==0) {
391     *prio=param.sched_priority;
392   }
393   return ret_value;
394 }
395
396 /**
397  * fosa_thread_set_prio()
398  *
399  * Dynamically change the priority of a thread
400  *
401  * The priority of the thread identified by tid is
402  * set to the value specified by prio. 
403  * 
404  * Returns 0 if successful, or the following error code:
405  *    EINVAL: the specified priority value is not between the 
406  *            minimum and the maximum priorities defined in this
407  *            FRSH implementation
408  * Alternatively, in case of error the implementation is allowed to
409  * notify it to the system console and then terminate the FRSH
410  * implementation and dependant applications
411  **/
412 int fosa_thread_set_prio(frsh_thread_id_t tid, int prio)
413 {
414   struct sched_param param;
415   int policy, ret_value;
416
417   ret_value=pthread_getschedparam(tid,&policy,&param);
418   if (ret_value!=0) return ret_value;
419
420   param.sched_priority=prio;
421   return pthread_setschedparam(tid,policy,&param);
422 }
423
424 /**
425  * fosa_thread_get_prio()
426  *
427  * Dynamically get the priority of a thread
428  *
429  * This function sets the variable pointed to by prio to the
430  * priority of the thread identified by tid
431  * 
432  * Returns 0
433  **/
434 int fosa_thread_get_prio (frsh_thread_id_t tid, int *prio)
435 {
436   struct sched_param param;
437   int policy, ret_value;
438
439   ret_value=pthread_getschedparam(tid,&policy,&param);
440   if (ret_value==0) {
441     *prio=param.sched_priority;
442   }
443   return ret_value;
444 }
445
446
447
448 /*******************************************************************
449  * Signals
450  *
451  * Signals represent events that may be notified by the system, or
452  * sent explicitly by the application, and for which a thread may
453  * synchronously wait. Signals carry an associated piece of
454  * information (an integer or a pointer) and are queued until they are
455  * accepted.  Signals are identified by an integer signal number (of
456  * the type frsh_signal_t) in the range FOSA_SIGNAL_MIN,
457  * FOSA_SIGNAL_MAX.  This range is required to have at least <tbd>
458  * values.
459  *******************************************************************/
460
461 /**
462  * fosa_set_accepted_signals()
463  *
464  * Establish the set of signals that may be synchronously accepted 
465  * by the calling thread
466  *
467  * The function uses the array of signal numbers specified by set,
468  * which must be of size equal to size
469  *
470  * Returns 0 if successful; otherwise it returns an error code:
471  *     EINVAL: the array contains one or more values which are not
472  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
473  *             is less than 0
474  *
475  * Alternatively, in case of error the implementation is allowed to
476  * notify it to the system console and then terminate the FRSH
477  * implementation and dependant applications
478  **/
479 int fosa_set_accepted_signals(frsh_signal_t set[], int size)
480 {
481   sigset_t signalset;
482   int i;
483   struct sigaction act;
484
485   // empty the signal set
486   CHKE(sigemptyset(&signalset));
487
488   // configure the signal action to make the signal a real-time
489   //   signal that can be queued
490   act.sa_handler=SIG_DFL;
491   act.sa_mask=signalset;
492   act.sa_flags=SA_SIGINFO;
493   act.sa_sigaction=NULL;
494
495     // loop for all signals in set
496   for(i=0;i<size;i++) {
497     CHKE(sigaddset(&signalset,set[i]));
498     // Configure the signal so that it can be queued with data
499     CHKE(sigaction(set[i],&act,NULL));
500   } 
501   return pthread_sigmask(SIG_BLOCK,&signalset,NULL);
502 }
503
504 /**
505  * fosa_signal_queue()
506  *
507  * Queue a signal
508  *
509  * This function is used to explicitly send a signal with a specified
510  * value
511  * 
512  * The signal number specified by signal is sent together with the
513  * information specified by info, to the thread identified by
514  * receiver. In those implementations that do not support queueing a
515  * signal with information to a thread (such as POSIX), the signal may
516  * be sent to any thread that is waiting for this signal via
517  * fosa_signal_wait(). Portability can be ensured by having the receiver
518  * thread be the one who is waiting for the signal. 
519  *
520  * Returns 0 if successful; otherwise it returns an error code:
521  *     EINVAL: the signal specified by signal is not
522  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
523  *
524  *     EAGAIN: no resources are available to queue the signal; the
525  *             maximum number of queued signals has been reached, or a
526  *             systemwide resource limit has been exceeded
527  *
528  * Alternatively, in case of error the implementation is allowed to
529  * notify it to the system console and then terminate the FRSH
530  * implementation and dependant applications
531  **/
532  int fosa_signal_queue
533        (frsh_signal_t signal, frsh_signal_info_t info,
534         frsh_thread_id_t receiver)
535 {
536   // note: in MaRTE OS the signal is sent to any interested thread
537   pid_t pid=1; // dummy value; the pid is ignored in MaRTE OS
538   int err;
539   err=sigqueue(pid,signal,*((union sigval *)(&info)));
540   // the above casting construct is used to overcome the compiler
541   // restriction that does not allow casts between unions
542   if (err==0) {
543     return 0;
544   } else {
545     return errno;
546   }
547 }
548
549
550 /**
551  * fosa_signal_wait()
552  *
553  * Wait for a signal
554  * 
555  * The function waits for the arrival of one of the signals in the
556  * array of signal numbers specified by set, which must be of size
557  * equal to size. If there is a signal already queued, the function
558  * returns immediately. If there is no signal of the specified set
559  * queued, the calling thread is suspended until a signal from that
560  * set arrives. Upon return, if signal_received is not NULL the number
561  * of the signal received is stored in the variable pointed to by
562  * signal_received; and if info is not NULL the associated information
563  * is stored in the variable pointed to by info.
564  *
565  * Returns 0 if successful; otherwise it returns an error code:
566  *     EINVAL: the array contains one or more values which are not
567  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
568  *             is less than 0
569  *
570  * Alternatively, in case of error the implementation is allowed to
571  * notify it to the system console and then terminate the FRSH
572  * implementation and dependant applications
573  **/
574  int fosa_signal_wait
575       (frsh_signal_t set[], int size, frsh_signal_t *signal_received, 
576        frsh_signal_info_t *info)
577 {
578   int err,i;
579   sigset_t signalset;
580   siginfo_t siginfo;
581
582   CHKE(sigemptyset(&signalset));
583   for(i=0;i<size;i++) {
584     CHKE(sigaddset(&signalset,set[i]));
585   } 
586
587   err=sigwaitinfo(&signalset,&siginfo);
588   if (err!=-1) {
589     *signal_received=siginfo.si_signo;
590     *info=*((frsh_signal_info_t *)(&siginfo.si_value));
591     return 0;
592   } else {
593     return errno;
594   }
595 }
596
597 /**
598  * fosa_signal_timedwait()
599  *
600  * Timed wait for a signal
601  * 
602  * This function behaves the same as fosa_signal_wait(), except that
603  * the suspension time is limited to the time interval specified in
604  * the timespec structure referenced by timeout.
605  * 
606  * Returns 0 if successful; otherwise it returns an error code:
607  *     EINVAL: the array contains one or more values which are not
608  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
609  *             is less than 0, or timeout is invalid
610  *     EAGAIN: The timeout expired
611  *
612  * Alternatively, in case of the EINVAL error the implementation is
613  * allowed to notify it to the system console and then terminate the
614  * FRSH implementation and dependant applications
615  **/
616  int fosa_signal_timedwait
617       (frsh_signal_t set[], int size, frsh_signal_t *signal_received, 
618        frsh_signal_info_t *info, const struct timespec *timeout)
619 {
620
621   // the implementation of sigtimedwait is not yet available in MaRTE OS
622   return ENOSYS;
623
624 /*   int err,i; */
625 /*   sigset_t signalset; */
626 /*   siginfo_t siginfo; */
627
628 /*   CHKE(sigemptyset(&signalset)); */
629 /*   for(i=0;i<size;i++) { */
630 /*     CHKE(sigaddset(&signalset,set[i])); */
631 /*   }  */
632
633 /*   err=sigtimedwait(&signalset,&siginfo,timeout); */
634 /*   if (err==0) { */
635 /*     *signal_received=siginfo.si_signo; */
636 /*     *info=siginfo.si_value; */
637 /*     return 0; */
638 /*   } else { */
639 /*     return errno; */
640 /*   } */
641 }
642