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