]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_ose/fosa_threads_and_signals.c
Last changes in FOSA Doxygen
[frescor/fosa.git] / src_ose / 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 //  All rights reserved.
24 //
25 //  Redistribution and use in source and binary forms, with or 
26 //  without modification, are permitted provided that the 
27 //  following conditions are met:
28 //
29 //    * Redistributions of source code must retain the above 
30 //      copyright notice, this list of conditions and the 
31 //      following disclaimer.
32 //    * Redistributions in binary form must reproduce the above 
33 //      copyright notice, this list of conditions and the 
34 //      following disclaimer in the documentation and/or other 
35 //      materials provided with the distribution.
36 //    * Neither the name of FRESCOR nor the names of its 
37 //      contributors may be used to endorse or promote products 
38 //      derived from this software without specific prior 
39 //      written permission.
40 //
41 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
42 //  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
43 //  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
44 //  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
45 //  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
46 //  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
47 //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
48 //  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
49 //  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
50 //  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
51 //  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
52 //  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
53 //  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
54 //  POSSIBILITY OF SUCH DAMAGE.
55 // -----------------------------------------------------------------------
56 //fosa_threads_and_signals.c
57 //==============================================
58 //  ********  ******    ********  **********
59 //  **///// /**    **  **//////  /**     /**
60 //  **      /**    ** /**        /**     /**
61 //  ******* /**    ** /********* /**********
62 //  **////  /**    ** ////////** /**//////**
63 //  **      /**    **        /** /**     /**
64 //  **      /**    **  ********  /**     /**
65 //  //       /******/  ////////   //      // 
66 //
67 // FOSA(Frescor Operating System Adaptation layer)
68 //================================================
69
70 #include <ose.h>
71 #include <stdio.h>
72 #include <heapapi.h>
73 #include <string.h>
74
75 #include "frsh_configuration_parameters.h"
76
77 #include "fosa.h"
78 #include "fosa_ose_implementation_specific.h"
79
80 /*
81  * author erth
82  *
83  * General entrypoint used when creating a process with POSIX look alike
84  * entrypoint. Recieves a signal and calls function received in signal 
85  * with arguments also received in signal.
86  */
87 static OS_PROCESS(fosa_ose_process_entrypoint)
88 {
89     static const SIGSELECT accepted_signal[] 
90                                        = { 1 ,FOSA_OSE_STARTUP_SIGNAL };
91     union SIGNAL* sig = receive(accepted_signal);
92     
93     switch(sig->sig_no) {
94         case FOSA_OSE_STARTUP_SIGNAL:
95         {
96             fosa_ose_signal_startup_t *startsig 
97                      = (fosa_ose_signal_startup_t *)sig;
98             
99             // Call FOSA entrypoint.
100             startsig->code( startsig->arg );
101             
102             break;
103         }
104         default:
105             // Call error() for all unexpected signals.
106             error2(0xFFFFFFFE, (OSERRCODE)sig);
107             break;
108     }
109     free_buf(&sig);   
110     kill_proc(current_process());
111 }
112
113 /**
114  * @defgroup threadandsignals Thread and Signals
115  * @ingroup fosa
116  *
117  * This module defines the functions that manipulate frsh_threads and
118  * frsh_signals inside FRSH implementation.
119  *
120  * Applications can refer to FRSH threads but they cannot create them
121  * directly, instead they must use frsh_thread_create*() which in turn
122  * use fosa_thread_create().
123  *
124  * For signals, we assume that the OS provides a direct mapping
125  * for frsh_signal_t and frsh_signal_info_t in the native interface.
126  *
127  * @{
128  **/
129
130
131
132 /*************************
133  * Thread identification
134  *************************/ 
135
136 /**
137  * fosa_thread_equal()
138  *
139  * Compare two thread identifiers to determine if they refer to the 
140  * same thread
141  **/
142  
143 bool fosa_thread_equal(frsh_thread_id_t t1, frsh_thread_id_t t2)
144 {
145     return (t1 == t2);
146 }
147
148
149 /**
150  * fosa_thread_self()
151  *
152  * Return the thread id of the calling thread
153  **/
154 frsh_thread_id_t fosa_thread_self() 
155 {
156     return current_process();
157 }
158
159 /*************************
160  * Thread creation and termination
161  *************************/ 
162
163 /**
164  * fosa_thread_create()
165  *
166  * This function creates a new thread using the attributes specified
167  * in attr. If attr is NULL, default attributes are used. The new
168  * thread starts running immediately, executing the function specified
169  * by code, with an argument equal to arg. Upon successful return, the
170  * variable pointed to by tid will contain the identifier of the newly
171  * created thread. The set of signals that may be synchronously
172  * accepted is inherited from the parent thread.
173  *
174  * Returns 0 if successful; otherwise it returs a code error:
175  *
176  *     EAGAIN: the system lacks the necessary resources to create a
177  *             new thread or the maximum number of threads has been
178  *             reached
179  *
180  *     EINVAL: the value specified by attr is invalid (for instance,
181  *              it has not been correctly initialized)
182  *
183  *     EREJECT: the cretion of the thread was rejected by the frsh scheduler
184  *               possibly because of incorrect attributes, or because the 
185  *               requested minimum capacity cannot be guaranteed
186  *
187  **/
188 int fosa_thread_create
189    (frsh_thread_id_t *tid, const frsh_thread_attr_t *attr, 
190     frsh_thread_code_t code, void * arg)
191 {
192     //Attributes
193     OSPRIORITY priority; 
194     OSADDRESS stack_size;
195     fosa_ose_process_info_t* NewProcess = 
196         (fosa_ose_process_info_t *)heap_alloc_shared(
197         sizeof(fosa_ose_process_info_t), __FILE__, __LINE__);
198     
199     //Initialize new node for fosa_ose_processes list.
200     if(attr == NULL) {
201         // If NULL, the lowest(!) OSE priority is used.
202         priority    = FRSH_HIGHEST_THREAD_PRIORITY;
203         stack_size  = 1000;
204         NewProcess->pid                 = 0; //Unknown at this stage.
205         NewProcess->app_scheduled       = false;
206         NewProcess->appsched_param      = NULL;
207         NewProcess->appsched_param_size = 0;
208     } else {
209         if ((attr->prio < fosa_get_priority_min()) ||
210             (attr->prio > fosa_get_priority_max())) {
211             return FOSA_EINVAL;
212         } 
213         priority    = attr->prio;
214         stack_size  = attr->stack_size;
215         NewProcess->pid                 = 0; //Unknown at this stage.
216         NewProcess->app_scheduled       = attr->app_scheduled;
217         NewProcess->appsched_param      = attr->appsched_param; //!............Kasst?
218         NewProcess->appsched_param_size = attr->appsched_param_size;
219     } 
220     NewProcess->nr_of_micros = 0;
221     NewProcess->nr_of_ticks  = 0;
222     
223     //Add new first node in fosa_ose_processes list.
224     NewProcess->NextProcess = fosa_ose_processes;
225     fosa_ose_processes = NewProcess;
226     
227     //Create process name
228     char name[25];
229     sprintf( name, "fosa_ose_%u", ++process_name_number );
230     
231     (*tid) = create_process(
232                    OS_PRI_PROC,         // Process type.                
233                    name,                // Name. 
234                    fosa_ose_process_entrypoint,// Entrypoint. 
235                    stack_size,          // Stacksize.           
236                    priority,            // Priority.                    
237                    0,                   // Timeslice.                   
238                    0,                   // 0 = Part of callers block.   
239                    NULL,                // No signal redirection.       
240                    0,                   // OSvector.                    
241                    0);                  // OSuser.          
242
243     fosa_ose_processes->pid = *tid;
244     
245     //Make the scheduler to call the new_thread callback.    
246     fosa_ose_send_event_to_scheduler(*tid, FOSA_OSE_NEW_THREAD_SIGNAL);
247     
248     //Receive from scheduler if accepted or rejected.    
249     SIGSELECT sel_reply[] = {2, FOSA_OSE_REJECT, FOSA_OSE_ACCEPT};
250     fosa_ose_event_signal_t *reply_sig;
251     reply_sig = (fosa_ose_event_signal_t *) receive(sel_reply);
252     if (reply_sig->sig_no != FOSA_OSE_ACCEPT) {
253         //event_sig->sig_no == FOSA_OSE_REJECT or something else.
254         fosa_ose_process_list_node_remove(0);
255         kill_proc(*tid); 
256         return FOSA_EREJECT;
257     }
258     
259     //New thread accepted
260     start(*tid);
261     
262     //Allocate, initialize and send signal with fosa entrypoint.
263     fosa_ose_signal_startup_t *entrypoint;
264     entrypoint = (fosa_ose_signal_startup_t *)
265                  alloc(sizeof(fosa_ose_signal_startup_t),
266                  FOSA_OSE_STARTUP_SIGNAL);
267     entrypoint->code = code;
268     entrypoint->arg  = arg;
269     send((union SIGNAL **)&entrypoint, *tid);
270     
271     return 0;
272 }
273
274
275 /**
276  * Note: no thread termination primitive is provided. The termination
277  * of a thread will be notifoed by the system to the FRSH scheduler
278  * through the scheduler API
279  **/
280
281
282 /**************************************************
283  * Thread-specific data
284  *  (extended with access from a different thread)
285  *
286  * Several data items (pointers) may be associated with each thread
287  * Each item is identified through a key, an integer value between 0
288  * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
289  * deallocating the memory area pointed to by the pointer
290  **************************************************/ 
291
292 /**
293  * fosa_key_create()
294  *
295  * Create a new key for thread specific data.
296  *
297  * Prior to setting data in a key, we need ask the system to create
298  * one for us.
299  *
300  * @return 0 if successful \n
301  *   FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
302  *   FOSA_ENOMEM If there are no enough memory resources to 
303  *               create the key.
304  **/
305 int fosa_key_create(int *key) {
306     /*
307      * author erth
308      *
309      * This function should return a new int each time it is called. If
310      * destroy is called for a number that int is freed and can be 
311      * returned again.
312      */
313     if (!fosa_ose_keys_initialized) {
314         memset(fosa_ose_keys_taken, false, sizeof(bool) * FOSA_MAX_KEYS);
315         fosa_ose_keys_initialized = true;
316     }        
317             
318     int i;
319     for (i = 0; i < FOSA_MAX_KEYS; i++) { 
320         if (fosa_ose_keys_taken[i] == false) break;
321     }
322     
323     if (i >= FOSA_MAX_KEYS) {
324         return FOSA_EINVAL;
325     }
326       
327     // First empty key found (number i).
328     fosa_ose_keys_taken[i] = true;
329     *key = i;
330     
331     return 0;
332 }
333
334 /**
335  * fosa_key_destroy()
336  *
337  * Destroy a key
338  *
339  * This destroys the key and isables its use in the system
340  *
341  * @return 0 if successful \n
342  *   FOSA_EINVAL The key is not initialised or is not in FOSA key range.
343  **/
344 int fosa_key_destroy(int key) {
345     fosa_ose_keys_taken[key] = false;
346     return 0;
347 }
348
349 /**
350  * fosa_thread_set_specific_data()
351  *
352  * Set thread-specific data
353  *
354  * For the thread identified by tid, the thread-specifid data field
355  * identified by key will be set to the value specified by value
356  *
357  * Returns 0 if successful; otherwise, an error code is returned
358  *     EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
359  *
360  * Alternatively, in case of error the implementation is allowed to
361  * notify it to the system console and then terminate the FRSH
362  * implementation and dependant applications
363  **/
364 int fosa_thread_set_specific_data
365       (int key, frsh_thread_id_t tid, const void * value) 
366 {
367     if ((key < 0) || 
368         (key > FOSA_MAX_KEYS-1)) {
369         return FOSA_EINVAL;
370     }
371     
372     char ose_key[30];
373     sprintf(ose_key, "fosa_key_%u", key);
374     
375     bool sucess = set_envp(tid, ose_key, (OSADDRESS) value);
376     
377     if (sucess) return 0;
378     else        return FOSA_EINVAL;
379 }
380     
381
382
383 /**
384  * fosa_thread_get_specific_data()
385  *
386  * Get thread-specific data
387  *
388  * For the thread identified by tid, the thread-specifid data field
389  * identified by key will be copied to the variable pointed to by value
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  * Alternatively, in case of error the implementation is allowed to
395  * notify it to the system console and then terminate the FRSH
396  * implementation and dependant applications
397  **/
398 int fosa_thread_get_specific_data(int key, frsh_thread_id_t tid, 
399                                   void ** value)
400 {
401     if ((key < 0) || 
402         (key > FOSA_MAX_KEYS-1)) {
403         return FOSA_EINVAL;
404     }
405     
406     char ose_key[30];
407     sprintf( ose_key, "fosa_key_%u", key );
408     
409     *value = (void*) get_envp(tid, ose_key);
410     
411     return 0;
412 }
413
414
415 /******************************************************************
416  * Thread scheduling
417  * 
418  * This implementation of FRSH assumes an underlying fixed priority
419  * scheduler with priorities in a range, with a minimum and a
420  * maximumm, a number of priority levels with at least 31
421  * priorities. A larger number implies a larger priority. In systems
422  * in which the underlying scheduler uses the opposite convention, a
423  * mapping is automatically provided by the OS adaptation layer.
424  *******************************************************************/
425
426 /**
427  * fosa_get_priority_max()
428  *
429  * Return the maximum priority value used in this implementation
430  **/
431 int fosa_get_priority_max() 
432 {
433     return FRSH_HIGHEST_THREAD_PRIORITY;
434 }
435 // Priority values in OSE are 0 - 31, where 0 represents the highest
436 // priority and 31 the lowest.
437
438 /**
439  * fosa_get_priority_min()
440  *
441  * Return the minimum priority value used in this implementation
442  **/
443 int fosa_get_priority_min() 
444 {
445     return FRSH_LOWEST_THREAD_PRIORITY;
446 }
447 // Priority values in OSE are 0 - 31, where 0 represents the highest
448 // priority and 31 the lowest.
449
450 /**
451  * fosa_thread_attr_set_prio()
452  *
453  * Change the priority of a thread attributes object
454  *
455  * The priority of the thread attriutes object specified by attr is
456  * set to the value specified by prio. This function has no runtime
457  * effect on the priority, except when the attributes object is used
458  * to create a thread, when it will be created with the specified
459  * priority
460  * 
461  * Returns 0 if successful, or the following error code:
462  *    EINVAL: the specified priority value is not between the 
463  *            minimum and the maximum priorities defined in this
464  *            FRSH implementation
465  * Alternatively, in case of error the implementation is allowed to
466  * notify it to the system console and then terminate the FRSH
467  * implementation and dependant applications
468  **/
469 int fosa_thread_attr_set_prio(frsh_thread_attr_t *attr, int prio) 
470 {
471     if ((prio < fosa_get_priority_min()) ||
472         (prio > fosa_get_priority_max())) {
473         return FOSA_EINVAL;
474     } 
475     else {
476         //Make ose priority from fosa priority, and set attr.
477         attr->prio = (OSPRIORITY) fosa_get_priority_max() 
478                           + fosa_get_priority_min() - prio;
479            
480         return 0;
481     }
482 }
483
484 /**
485  * fosa_thread_attr_get_prio()
486  *
487  * Get the priority from a thread attributes object
488  *
489  * This function sets the variable pointed to by prio to the
490  * priority stored in the thread attributes object attr.
491  * 
492  * Returns 0
493  **/
494 int fosa_thread_attr_get_prio
495           (const frsh_thread_attr_t *attr, size_t *prio) 
496 {
497     // Map OSE priority to FOSA priority.
498     *prio = fosa_get_priority_max() +  fosa_get_priority_min() 
499             - (int) attr->prio;
500     
501     return 0;            
502 }
503
504 /**
505  * fosa_thread_set_prio()
506  *
507  * Dynamically change the priority of a thread
508  *
509  * The priority of the thread identified by tid is
510  * set to the value specified by prio. 
511  * 
512  * Returns 0 if successful, or the following error code:
513  *    EINVAL: the specified priority value is not between the 
514  *            minimum and the maximum priorities defined in this
515  *            FRSH implementation
516  * Alternatively, in case of error the implementation is allowed to
517  * notify it to the system console and then terminate the FRSH
518  * implementation and dependant applications
519  **/
520 int fosa_thread_set_prio(frsh_thread_id_t tid, int prio) 
521 {
522     if ((prio < fosa_get_priority_min()) || 
523         (prio > fosa_get_priority_max())) {
524         return FOSA_EINVAL;
525     }
526     // Map FOSA priority to OSE priority.
527     OSPRIORITY new_ose_prio = (OSPRIORITY) fosa_get_priority_max() 
528                           + fosa_get_priority_min() - prio;
529                           
530     OSPRIORITY org_prio = get_pri(tid);
531     
532     if (org_prio == new_ose_prio) return 0; 
533     
534     int new_prio = set_pri_for(tid, new_ose_prio);
535     if(new_prio == org_prio) {
536         return FOSA_EINVAL;
537     } else {
538         return 0;
539     }
540 }
541
542 /**
543  * fosa_thread_get_prio()
544  *
545  * Dynamically get the priority of a thread
546  *
547  * This function sets the variable pointed to by prio to the
548  * priority of the thread identified by tid
549  * 
550  * Returns 0
551  **/
552 int fosa_thread_get_prio (frsh_thread_id_t tid, int *prio)
553 {
554     OSPRIORITY ose_prio = get_pri(tid);
555     // Map OSE priority to FOSA priority.
556     *prio = fosa_get_priority_max() +  fosa_get_priority_min() 
557             - (int) ose_prio;
558     return 0;
559 }
560
561
562
563 /*******************************************************************
564  * Signals
565  *
566  * Signals represent events that may be notified by the system, or
567  * sent explicitly by the application, and for which a thread may
568  * synchronously wait. Signals carry an associated piece of
569  * information (an integer or a pointer) and are queued until they are
570  * accepted.  Signals are identified by an integer signal number (of
571  * the type frsh_signal_t) in the range FOSA_SIGNAL_MIN,
572  * FOSA_SIGNAL_MAX.  This range is required to have at least <tbd>
573  * values.
574  *******************************************************************/
575
576 /**
577  * fosa_set_accepted_signals()
578  *
579  * Establish the set of signals that may be synchronously accepted 
580  * by the calling thread
581  *
582  * The function uses the array of signal numbers specified by set,
583  * which must be of size equal to size
584  *
585  * Returns 0 if successful; otherwise it returns an error code:
586  *     EINVAL: the array contains one or more values which are not
587  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
588  *             is less than 0
589  *
590  * Alternatively, in case of error the implementation is allowed to
591  * notify it to the system console and then terminate the FRSH
592  * implementation and dependant applications
593  **/
594 int fosa_set_accepted_signals(frsh_signal_t set[], int size) 
595 {
596     /*
597      * author erth
598      *
599      * This function is not neccisary in OSE since set[] is used as an 
600      * argument in the calls to fosa_signal_wait() and 
601      * fosa_signal_timedwait() functions. Also decided to be empty in 
602      * Barcelona meeting 2007-01-31.
603      */
604     return 0;
605 }  
606
607
608 /**
609  * fosa_signal_queue()
610  *
611  * Queue a signal
612  *
613  * This function is used to explicitly send a signal with a specified
614  * value
615  * 
616  * The signal number specified by signal is sent together with the
617  * information specified by info, to the thread identified by
618  * receiver. In those implementations that do not support queueing a
619  * signal with information to a thread (such as POSIX), the signal may
620  * be sent to any thread that is waiting for this signal via
621  * fosa_signal_wait(). Portability can be ensured by having the receiver
622  * thread be the one who is waiting for the signal. 
623  *
624  * Returns 0 if successful; otherwise it returns an error code:
625  *     EINVAL: the signal specified by signal is not
626  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
627  *
628  *     EAGAIN: no resources are available to queue the signal; the
629  *             maximum number of queued signals has been reached, or a
630  *             systemwide resource limit has been exceeded
631  *
632  * Alternatively, in case of error the implementation is allowed to
633  * notify it to the system console and then terminate the FRSH
634  * implementation and dependant applications
635  **/
636 int fosa_signal_queue
637      (frsh_signal_t signal, frsh_signal_info_t info,
638       frsh_thread_id_t receiver)
639 {
640     if ((signal < FOSA_SIGNAL_MIN) || (signal > FOSA_SIGNAL_MAX)) {
641         return FOSA_EINVAL;
642     }
643     
644     fosa_ose_signal_t *ose_sig;
645     ose_sig = (fosa_ose_signal_t *)
646                   alloc(sizeof(fosa_ose_signal_t), signal);
647     
648     ose_sig->info = info;
649     send((union SIGNAL **)&ose_sig, receiver); 
650     
651     //Other errors taken care of by OSE.
652     return 0;
653 }       
654
655
656 /**
657  * fosa_signal_queue_scheduler()
658  *
659  * Queue a signal destinated to the scheduler
660  *
661  * This is a special case of fosa_signal_queue() in which the
662  * destinator is the scheduler itself.  It is needed by the service
663  * thread to notify the results to the scheduler.
664  *
665  * The problem with this case is that, depending on the implementation,
666  * this call would be translated to a true signal or to a scheduler
667  * notification message.
668  *
669  * Besides for the scheduler we don't have always a destinator
670  * thread_id needed in frsh_signal_queue for OSE.
671  *
672  * So the fosa implementation will solve this issue internally.
673  * 
674  * Returns 0 if successful; otherwise it returns an error code:
675  *     EINVAL: the signal specified by signal is not
676  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
677  *
678  *     EAGAIN: no resources are available to queue the signal; the
679  *             maximum number of queued signals has been reached, or a
680  *             systemwide resource limit has been exceeded
681  *
682  * Alternatively, in case of error the implementation is allowed to
683  * notify it to the system console and then terminate the FRSH
684  * implementation and dependant applications
685  **/
686 int fosa_signal_queue_scheduler(frsh_signal_t signal, 
687                                 frsh_signal_info_t info) {
688     PROCESS scheduler;
689     hunt("fosa_scheduler_process", 0, &scheduler, (union SIGNAL **) NULL);
690     if (scheduler == 0) return EINVAL;
691     
692     return fosa_signal_queue(signal, info, scheduler);
693 }
694
695
696 /**
697  * fosa_signal_wait()
698  *
699  * Wait for a signal
700  * 
701  * The function waits for the arrival of one of the signals in the
702  * array of signal numbers specified by set, which must be of size
703  * equal to size. If there is a signal already queued, the function
704  * returns immediately. If there is no signal of the specified set
705  * queued, the calling thread is suspended until a signal from that
706  * set arrives. Upon return, if signal_received is not NULL the number
707  * of the signal received is stored in the variable pointed to by
708  * signal_received; and if info is not NULL the associated information
709  * is stored in the variable pointed to by info.
710  *
711  * Returns 0 if successful; otherwise it returns an error code:
712  *     EINVAL: the array contains one or more values which are not
713  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
714  *             is less than 0
715  *
716  * Alternatively, in case of error the implementation is allowed to
717  * notify it to the system console and then terminate the FRSH
718  * implementation and dependant applications
719  **/
720 int fosa_signal_wait
721      (frsh_signal_t set[], int size, frsh_signal_t *signal_received, 
722       frsh_signal_info_t *info) 
723 {
724     if (size < 0) return FOSA_EINVAL;
725     int i = 0;
726     for (i = 0; i < size; ++i) {
727         if ((set[i] < FOSA_SIGNAL_MIN) || 
728             (set[i] > FOSA_SIGNAL_MAX)) {
729             return FOSA_EINVAL;
730         }       
731     }
732     // No check for signals before receiving is needed.
733     
734     // Receive
735     SIGSELECT sig_set[size+1];
736     sig_set[0] = size;
737     for (i = 1; i < size+1; ++i) 
738         sig_set[i] = set[i-1];
739     union SIGNAL *ose_sig_union;
740     ose_sig_union = receive(sig_set);
741         
742     fosa_ose_signal_t *ose_sig = 
743         (fosa_ose_signal_t *)ose_sig_union;
744     
745     // Return
746     if( signal_received != NULL ) 
747         *signal_received = ose_sig->sig_no;
748     if( info != NULL )  
749         *info = ose_sig->info;
750     
751     free_buf(&ose_sig_union);
752     
753     return 0;
754 }       
755
756
757 /**
758  * fosa_signal_timedwait()
759  *
760  * Timed wait for a signal
761  * 
762  * This function behaves the same as fosa_signal_wait(), except that
763  * the suspension time is limited to the time interval specified in
764  * the timespec structure referenced by timeout.
765  * 
766  * Returns 0 if successful; otherwise it returns an error code:
767  *     EINVAL: the array contains one or more values which are not
768  *             between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
769  *             is less than 0, or timeout is invalid
770  *     EAGAIN: The timeout expired
771  *
772  * Alternatively, in case of the EINVAL error the implementation is
773  * allowed to notify it to the system console and then terminate the
774  * FRSH implementation and dependant applications
775  **/
776 int fosa_signal_timedwait
777      (frsh_signal_t set[], int size, frsh_signal_t *signal_received, 
778       frsh_signal_info_t *info, const struct timespec *timeout)
779 {
780     if (size < 0) return FOSA_EINVAL;
781     int i = 0;
782     for (i = 0; i < size; ++i) {
783         if ((set[i] < FOSA_SIGNAL_MIN) || 
784             (set[i] > FOSA_SIGNAL_MAX)) {
785             return FOSA_EINVAL;
786         }       
787     }
788     // No check for signals before receiving is needed.
789     
790     // Receive
791     SIGSELECT sig_set[size+1];
792     sig_set[0] = size;
793     for (i = 1; i < size+1; ++i) 
794         sig_set[i] = set[i-1];
795         
796     OSTIME millisec = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000;
797     
798     union SIGNAL *ose_sig_union;
799     ose_sig_union = receive_w_tmo(millisec, sig_set);
800     
801     // Timed out?
802     if(ose_sig_union == NIL) return FOSA_EAGAIN; 
803         
804     fosa_ose_signal_t *ose_sig = 
805         (fosa_ose_signal_t *)ose_sig_union;
806     
807     // Return
808     if( signal_received != NULL ) 
809         *signal_received = ose_sig->sig_no;
810     if( info != NULL )  
811         *info = ose_sig->info;
812     
813     free_buf(&ose_sig_union);
814        
815     return 0;
816 }   
817
818 /*}*/