]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_aquosa/fosa_threads_and_signals.c
1cb47959fffe0fa3322250bc5460e10fef904faa
[frescor/fosa.git] / src_aquosa / fosa_threads_and_signals.c
1 // -----------------------------------------------------------------------
2 //  Copyright (C) 2006 - 2007 FRESCOR consortium partners:
3 //
4 //    Universidad de Cantabria,              SPAIN
5 //    University of York,                    UK
6 //    Scuola Superiore Sant'Anna,            ITALY
7 //    Kaiserslautern University,             GERMANY
8 //    Univ. Politecnica  Valencia,           SPAIN
9 //    Czech Technical University in Prague,  CZECH REPUBLIC
10 //    ENEA                                   SWEDEN
11 //    Thales Communication S.A.              FRANCE
12 //    Visual Tools S.A.                      SPAIN
13 //    Rapita Systems Ltd                     UK
14 //    Evidence                               ITALY
15 //    
16 //    See http://www.frescor.org for a link to partners' websites
17 //
18 //           FRESCOR project (FP6/2005/IST/5-034026) is funded
19 //        in part by the European Union Sixth Framework Programme
20 //        The European Union is not liable of any use that may be
21 //        made of this code.
22 //
23 //  This file is part of the FRSH implementation
24 //
25 //  FRSH is free software; you can  redistribute it and/or  modify
26 //  it under the terms of  the GNU General Public License as published by
27 //  the Free Software Foundation;  either  version 2, or (at  your option)
28 //  any later version.
29 //
30 //  FRSH  is distributed  in  the hope  that  it  will  be useful,  but
31 //  WITHOUT  ANY  WARRANTY;     without  even the   implied   warranty  of
32 //  MERCHANTABILITY  or  FITNESS FOR  A  PARTICULAR PURPOSE. See  the  GNU
33 //  General Public License for more details.
34 //
35 //  You should have  received a  copy of  the  GNU  General Public License
36 //  distributed  with  FRSH;  see file COPYING.   If not,  write to the
37 //  Free Software  Foundation,  59 Temple Place  -  Suite 330,  Boston, MA
38 //  02111-1307, USA.
39 //
40 //  As a special exception, if you include this header file into source
41 //  files to be compiled, this header file does not by itself cause
42 //  the resulting executable to be covered by the GNU General Public
43 //  License.  This exception does not however invalidate any other
44 //  reasons why the executable file might be covered by the GNU General
45 //  Public License.
46 // -----------------------------------------------------------------------
47 //==============================================
48 //  ********  ******    ********  **********
49 //  **///// /**    **  **//////  /**     /**
50 //  **      /**    ** /**        /**     /**
51 //  ******* /**    ** /********* /**********
52 //  **////  /**    ** ////////** /**//////**
53 //  **      /**    **        /** /**     /**
54 //  **      /**    **  ********  /**     /**
55 //  //       /******/  ////////   //      // 
56 //
57 // FOSA(Frescor Operating System Adaptation layer)
58 //================================================
59
60 #include "fosa_time.h"
61 #include "fosa_configuration_parameters.h"
62 #include "fosa_threads_and_signals.h"
63
64 /*************************
65  * Storage of thread-specific keys
66  *************************/
67
68 static pthread_key_t key_list[FOSA_MAX_KEYS];
69 static bool key_in_use[FOSA_MAX_KEYS];
70 static pthread_mutex_t key_lock;
71
72
73 /* Initialize the keys data structure */
74 int init_keys()
75 {
76         int i, error;
77         pthread_mutexattr_t attr;
78
79         for(i = 0; i < FOSA_MAX_KEYS; i++)
80                 key_in_use[i] = false;
81
82         if ((error = pthread_mutexattr_init(&attr)) != 0)
83                 return error;
84
85         if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0)
86                 return error;
87
88         if ((error = pthread_mutex_init(&key_lock,&attr)) != 0)
89                 return error;
90
91         return 0;
92 }
93
94 /*************************
95  * Thread identification
96  *************************/ 
97
98 /**
99  * fosa_thread_equal()
100  *
101  * Compare two thread identifiers to determine if they refer to the 
102  * same thread
103  **/
104 bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2)
105 {
106         return t1.linux_pid == t2.linux_pid &&
107                t1.linux_tid == t2.linux_tid &&
108                pthread_equal(t1.pthread_id, t2.pthread_id);
109 }
110
111 /**
112  * fosa_thread_self()
113  *
114  * Return the thread id of the calling thread
115  **/
116 fosa_thread_id_t fosa_thread_self()
117 {
118         fosa_thread_id_t thread_self;
119         /** 
120          * NB. Remember:
121          *  fosa_thread_id_t => struct {
122          *                       pthread_t pthread_id;
123          *                       pid_t linux_pid;
124          *                       tid_t linux_tid;
125          * };
126          **/
127         thread_self.pthread_id = pthread_self();
128         thread_self.linux_pid = getpid();
129         thread_self.linux_tid = syscall(__NR_gettid);   /* gettid() */
130
131         return thread_self;
132 }
133
134 /*************************
135  * Thread attributes
136  *************************/
137
138 /**
139  * fosa_thread_attr_init()
140  *
141  * Initialize a thread attributes object
142  *
143  * This function initializes the object pointed to by attr to all 
144  * the default values defined by FRSH
145  *
146  * return 0 if successful; otherwise it returns
147  *   FOSA_ENOMEM: insufficient memory exists to initialize the thread 
148  *           attributes object
149  **/
150 int fosa_thread_attr_init(fosa_thread_attr_t *attr)
151 {
152         fosa_thread_id_t self;
153
154         /* only POSIX threads have attributes */
155         self = fosa_thread_self();
156         if (self.linux_pid == self.linux_tid)
157                 return EINVAL;
158
159         return pthread_attr_init(attr);
160 }
161
162 /**
163  * fosa_thread_attr_destroy()
164  *
165  * Destroy a thread attributes object
166  *
167  * This function is used to destroy the thread attributes object,
168  * pointed to by attr, and deallocate any system resources allocated for it
169  * 
170  * Returns 0
171  **/
172 int fosa_thread_attr_destroy(fosa_thread_attr_t *attr)
173 {
174         fosa_thread_id_t self;
175
176         /* only POSIX threads can have attributes */
177         self = fosa_thread_self();
178         if (self.linux_pid == self.linux_tid)
179                 return EINVAL;
180
181         return pthread_attr_destroy(attr);
182 }
183
184 /**
185  * fosa_thread_attr_set_stacksize()
186  *
187  * Set the thread minimum stack size in a thread attributes object
188  *
189  * This function sets the minimum stack size of the thread attributes
190  * object attr to the value given by stacksize, in bytes. This
191  * function has no runtime effect on the stack size, except when the
192  * attributes object is used to create a thread, when it will be
193  * created with the specified minimum stack size
194  * 
195  * return 0 if successful, or the following error code:
196  *    FOSA_EINVAL: the specified stacksize  value is not supported in
197  *            this implementation
198  **/
199 int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr,
200                                    size_t stacksize)
201 {
202         fosa_thread_id_t self;
203
204         /* only POSIX threads can set the size of the stack */
205         self = fosa_thread_self();
206         if (self.linux_pid == self.linux_tid)
207                 return EINVAL;
208
209         return pthread_attr_setstacksize(attr, stacksize);
210 }
211
212 /**
213  * fosa_thread_attr_get_stacksize()
214  *
215  * Get the thread minimum stack size from a thread attributes object
216  *
217  * This function sets the variable pointed to by stacksize to the
218  * minimum stack size stored in the thread attributes object attr.
219  * 
220  * return 0
221  **/
222 int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr,
223                                    size_t *stacksize)
224 {
225         fosa_thread_id_t self;
226
227         /* only POSIX threads can set the size of the stack */
228         self = fosa_thread_self();
229         if (self.linux_pid == self.linux_tid)
230                 return EINVAL;
231
232         return pthread_attr_getstacksize(attr, stacksize);
233 }
234
235 /*************************
236  * Thread creation and termination
237  *************************/
238
239 /**
240  * fosa_thread_create()
241  *
242  * This function creates a new thread using the attributes specified
243  * in attr. If attr is NULL, default attributes are used. The new
244  * thread starts running immediately, executing the function specified
245  * by code, with an argument equal to arg. Upon successful return, the
246  * variable pointed to by tid will contain the identifier of the newly
247  * created thread. The set of signals that may be synchronously
248  * accepted is inherited from the parent thread.
249  *
250  * Returns 0 if successful; otherwise it returs a code error:
251  *
252  *     EAGAIN: the system lacks the necessary resources to create a
253  *             new thread or the maximum number of threads has been
254  *             reached
255  *
256  *     EINVAL: the value specified by attr is invalid (for instance,
257  *              it has not been correctly initialized)
258  *
259  *     EREJECT: the cretion of the thread was rejected by the frsh scheduler
260  *               possibly because of incorrect attributes, or because the 
261  *               requested minimum capacity cannot be guaranteed
262  **/
263 int fosa_thread_create(fosa_thread_id_t *tid,
264                        const fosa_thread_attr_t *attr,
265                        fosa_thread_code_t code,
266                        void *arg)
267 {
268         return pthread_create(&tid->pthread_id, attr, code, arg);
269 }
270
271 /**
272  * Note: no thread termination primitive is provided. The termination
273  * of a thread will be notified by the system to the FRSH scheduler
274  * through the scheduler API
275  **/
276
277 /**************************************************
278  * Thread-specific data
279  *  (extended with access from a different thread)
280  *
281  * Several data items (pointers) may be associated with each thread
282  * Each item is identified through a key, an integer value between 0
283  * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
284  * deallocating the memory area pointed to by the pointer
285  **************************************************/ 
286
287 /**
288  * fosa_key_create()
289  *
290  * Create a new key for thread specific data.
291  *
292  * Prior to setting data in a key, we need ask the system to create
293  * one for us.
294  *
295  * return 0 if successful \n
296  *   FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
297  *   FOSA_ENOMEM If there are no enough memory resources to 
298  *               create the key.
299  **/
300 int fosa_key_create(int *key)
301 {
302         int i, error = 0;
303         bool found = false;
304         fosa_thread_id_t self;
305
306         /* only POSIX threads can have specific data */
307         self = fosa_thread_self();
308         if (self.linux_pid == self.linux_tid)
309                 return EINVAL;
310
311         if ((error = pthread_mutex_lock(&key_lock)) != 0)
312                 return error;
313
314         /* find an unused key */
315         for (i = 0; i < FOSA_MAX_KEYS; i++) {
316                 if (!key_in_use[i]) {
317                         *key = i;
318                         key_in_use[i] = true;
319                         error = pthread_key_create(&(key_list[i]), NULL);
320                         found = true;
321                         break;
322                 }
323         }
324
325         if ((error = pthread_mutex_unlock(&key_lock))!= 0)
326                 return error;
327
328         return (!found ? FOSA_EINVAL : error);
329 }
330
331 /**
332  * fosa_key_destroy()
333  *
334  * Destroy a key
335  *
336  * This destroys the key and isables its use in the system
337  *
338  * return 0 if successful
339  *   FOSA_EINVAL The key is not initialised or is not in FOSA key range.
340  **/
341 int fosa_key_destroy(int key)
342 {
343         int error;
344         fosa_thread_id_t self;
345
346         /* only POSIX threads can have specific data */
347         self = fosa_thread_self();
348         if (self.linux_pid == self.linux_tid)
349                 return EINVAL;
350
351         if ((error = pthread_mutex_lock(&key_lock)) != 0)
352                 return error;
353
354         if ((error = pthread_key_delete(key_list[key])) != 0)
355                 key_in_use[key]=false;
356
357         if ((error = pthread_mutex_unlock(&key_lock)) != 0)
358                 return error;
359
360         return 0;
361 }
362
363
364 /**
365  * fosa_thread_set_specific_data()
366  *
367  * Set thread-specific data
368  *
369  * For the thread identified by tid, the thread-specifid data field
370  * identified by key will be set to the value specified by value
371  * 
372  * In this implementation, according to POSIX, the accessed data field
373  * is the one of the calling thread, not the one specified via tid.
374  *
375  * Returns 0 if successful; otherwise, an error code is returned
376  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
377  **/
378  int fosa_thread_set_specific_data(int key,
379                                    fosa_thread_id_t tid,
380                                    const void * value)
381 {
382         fosa_thread_id_t self;
383
384         /* only POSIX threads can have specific data */
385         self = fosa_thread_self();
386         if (self.linux_pid == self.linux_tid)
387                 return EINVAL;
388
389         return pthread_setspecific(key_list[key], value);
390 }
391
392 /**
393  * fosa_thread_get_specific_data()
394  *
395  * Get thread-specific data
396  *
397  * For the thread identified by tid, the thread-specifid data field
398  * identified by key will be copied to the variable pointed to by value
399  * 
400  * In this implementation, according to POSIX, the accessed data field
401  * is the one of the calling thread, not the one specified via tid.
402  *
403  * Returns 0 if successful; otherwise, an error code is returned
404  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
405  **/
406 int fosa_thread_get_specific_data(int key,
407                                   fosa_thread_id_t tid,
408                                   void ** value)
409 {
410         fosa_thread_id_t self;
411
412         /* only POSIX threads can have specific data */
413         self = fosa_thread_self();
414         if (self.linux_pid == self.linux_tid)
415                 return EINVAL;
416
417         if ((value = pthread_getspecific(key_list[key])) != NULL)
418                 return EINVAL;
419         else
420                 return 0;
421 }
422
423 /******************************************************************
424  * Thread scheduling
425  * 
426  * This implementation of FRSH assumes an underlying fixed priority
427  * scheduler with priorities in a range, with a minimum and a
428  * maximumm, a number of priority levels with at least 31
429  * priorities. A larger number implies a larger priority. In systems
430  * in which the underlying scheduler uses the opposite convention, a
431  * mapping is automatically provided by the OS adaptation layer.
432  *******************************************************************/
433
434 /**
435  * fosa_get_priority_max()
436  *
437  * Return the maximum priority value used in this implementation
438  **/
439 int fosa_get_priority_max()
440 {
441         return sched_get_priority_max(SCHED_RR);
442 }
443
444 /**
445  * fosa_get_priority_min()
446  *
447  * Return the minimum priority value used in this implementation
448  **/
449 int fosa_get_priority_min()
450 {
451         return sched_get_priority_min(SCHED_RR);
452 }
453
454 /**
455  * fosa_thread_attr_set_prio()
456  *
457  * Change the priority of a thread attributes object
458  *
459  * The priority of the thread attriutes object specified by attr is
460  * set to the value specified by prio. This function has no runtime
461  * effect on the priority, except when the attributes object is used
462  * to create a thread, when it will be created with the specified
463  * priority
464  * 
465  * Returns 0 if successful, or the following error code:
466  *    EINVAL: the specified priority value is not between the 
467  *            minimum and the maximum priorities defined in this
468  *            FRSH implementation
469  **/
470 int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio)
471 {
472         int error;
473         fosa_thread_id_t self;
474         struct sched_param param;
475
476         /* normal UNIX processes have no attributes */
477         self = fosa_thread_self();
478         if (self.linux_pid == self.linux_tid)
479                 return EINVAL;
480         
481         param.sched_priority = prio;
482         if ((error = pthread_attr_setschedpolicy(attr, SCHED_RR)) == 0)
483                 return error;
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  * Alternatively, in case of error the implementation is allowed to
586  * notify it to the system console and then terminate the FRSH
587  * implementation and dependant applications
588  **/
589 int fosa_set_accepted_signals(fosa_signal_t set[], int size)
590 {
591         int i, error;
592         fosa_thread_id_t self;
593         sigset_t sigset;
594         struct sigaction action;
595
596         if ((error = sigemptyset(&sigset)) != 0)
597                 return error;
598
599         action.sa_handler = SIG_DFL;
600         action.sa_mask = sigset;
601         action.sa_flags = SA_SIGINFO;
602         action.sa_sigaction = NULL;
603
604         for (i = 0; i < size; i++) {
605                 if ((error = sigaddset(&sigset, set[i])) != 0)
606                         return error;
607                 if ((error = sigaction(set[i], &action, NULL)) != 0)
608                         return error;
609         }
610
611         self = fosa_thread_self();
612         if (self.linux_pid == self.linux_tid)
613                 return pthread_sigmask(SIG_BLOCK, &sigset, NULL);
614         else
615                 return sigprocmask(SIG_BLOCK, &sigset, NULL);
616 }
617
618 /**
619  * fosa_signal_queue()
620  *
621  * Queue a signal
622  *
623  * This function is used to explicitly send a signal with a specified
624  * value
625  * 
626  * The signal number specified by signal is sent together with the
627  * information specified by info, to the thread identified by
628  * receiver. In those implementations that do not support queueing a
629  * signal with information to a thread (such as POSIX), the signal may
630  * be sent to any thread that is waiting for this signal via
631  * fosa_signal_wait(). Portability can be ensured by having the receiver
632  * thread be the one who is waiting for the signal. 
633  *
634  * In this implementation, this limitation has been overcome by means
635  * of the Linux specific capability of sending a timer event directly
636  * to a specific thread. Thus, we program a fake timer to fire immediately
637  * and notify such event to the requested receiver thread.
638  *
639  * Returns 0 if successful; otherwise it returns an error code:
640  *     EINVAL: the signal specified by signal is not
641  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
642  *
643  *     EAGAIN: no resources are available to queue the signal; the
644  *             maximum number of queued signals has been reached, or a
645  *             systemwide resource limit has been exceeded
646  *
647  * Alternatively, in case of error the implementation is allowed to
648  * notify it to the system console and then terminate the FRSH
649  * implementation and dependant applications
650  **/
651 int fosa_signal_queue(fosa_signal_t signal,
652                       fosa_signal_info_t info,
653                       fosa_thread_id_t receiver)
654 {
655         int error;
656         timer_t fake_timer;
657         struct itimerspec fake_time;
658         struct sigevent fake_event;
659
660         timer_create(CLOCK_MONOTONIC, &fake_event, &fake_timer);
661
662         fake_time.it_value.tv_sec = fake_time.it_value.tv_nsec = 0;
663         fake_time.it_interval.tv_sec = fake_time.it_interval.tv_nsec = 0;
664         fake_event.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
665         fake_event.sigev_signo  = SIGRTMIN;
666         fake_event.sigev_value.sival_int = info.sival_int;
667         fake_event._sigev_un._tid = receiver.linux_tid;
668
669         error = timer_settime(fake_timer, TIMER_ABSTIME, &fake_time, NULL);
670         timer_delete(fake_timer);
671
672         return error;
673 }
674
675 /**
676  * fosa_signal_wait()
677  *
678  * Wait for a signal
679  * 
680  * The function waits for the arrival of one of the signals in the
681  * array of signal numbers specified by set, which must be of size
682  * equal to size. If there is a signal already queued, the function
683  * returns immediately. If there is no signal of the specified set
684  * queued, the calling thread is suspended until a signal from that
685  * set arrives. Upon return, if signal_received is not NULL the number
686  * of the signal received is stored in the variable pointed to by
687  * signal_received; and if info is not NULL the associated information
688  * is stored in the variable pointed to by info.
689  *
690  * Returns 0 if successful; otherwise it returns an error code:
691  *     EINVAL: the array contains one or more values which are not
692  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
693  *             is less than 0
694  *
695  * Alternatively, in case of error the implementation is allowed to
696  * notify it to the system console and then terminate the FRSH
697  * implementation and dependant applications
698  **/
699 int fosa_signal_wait(fosa_signal_t set[], int size,
700                      fosa_signal_t *signal_received,
701                      fosa_signal_info_t *info)
702 {
703         int i, error;
704         sigset_t sigset;
705         siginfo_t siginfo;
706
707         if ((error = sigemptyset(&sigset)) != 0)
708                 return error;
709
710         for (i = 0; i < size; i++)
711                 if ((error = sigaddset(&sigset,set[i])) != 0)
712                         return error;
713
714         if ((error = sigwaitinfo(&sigset, &siginfo)) != 0)
715                 return error;
716
717         if (info != NULL && signal_received != NULL)
718                 *signal_received = siginfo.si_signo;
719         if (info != NULL)
720                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
721
722         return 0;
723 }
724
725 /**
726  * fosa_signal_timedwait()
727  *
728  * Timed wait for a signal
729  * 
730  * This function behaves the same as fosa_signal_wait(), except that
731  * the suspension time is limited to the time interval specified in
732  * the timespec structure referenced by timeout.
733  * 
734  * Returns 0 if successful; otherwise it returns an error code:
735  *     EINVAL: the array contains one or more values which are not
736  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
737  *             is less than 0, or timeout is invalid
738  *     EAGAIN: The timeout expired
739  *
740  * Alternatively, in case of error the implementation is allowed to
741  * notify it to the system console and then terminate the FRSH
742  * implementation and dependant applications
743  **/
744 int fosa_signal_timedwait(fosa_signal_t set[], int size,
745                           fosa_signal_t *signal_received,
746                           fosa_signal_info_t *info,
747                           const struct timespec *timeout)
748 {
749         int i, error;
750         sigset_t signalset;
751         siginfo_t siginfo;
752
753         if ((error = sigemptyset(&signalset)) != 0)
754                 return error;
755
756         for (i = 0; i < size; i++)
757                 if ((error = sigaddset(&signalset,set[i])) != 0)
758                         return error;
759
760         if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0)
761                 return error;
762
763         if (signal_received != NULL)
764                 *signal_received = siginfo.si_signo;
765         if (info != NULL)
766                 *info = (fosa_signal_info_t) siginfo.si_value.sival_int;
767
768         return 0;
769 }
770