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