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