]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_ose/fosa_mutexes_and_condvars.c
Makefile: Add missing header file
[frescor/fosa.git] / src_ose / fosa_mutexes_and_condvars.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_mutexes_and_condvars.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
72 #include "frsh_configuration_parameters.h"
73
74 #include "fosa.h"
75 #include "fosa_ose_implementation_specific.h"
76
77 /**
78  * @defgroup mutexesandcondvars Mutexes and Condvars
79  * @ingroup fosa
80  *
81  * This module defines the types and functions to abstract mutexes and
82  * conditional variables for the FRSH implementation.
83  *
84  * @{
85  **/
86
87 /*******************************************************
88  * Mutexes with priority ceiling
89  ******************************************************/
90
91 /**
92  * fosa_mutex_init()
93  *
94  * Initialize a frsh mutex
95  *
96  * The mutex pointed to by mutex is initialized as a mutex using 
97  * the priority ceiling protocol. A priority ceiling of prioceiling
98  * is assigned to this mutex.
99  * 
100  * Returns 0 if successful; otherwise it returns an error code:
101  *    EINVAL: the value of prioceiling is invalid
102  *    EAGAIN: the system lacked the necessary resources to create the mutex
103  *    ENOMEM: Insufficient memory exists to initialize the mutex
104  *    EBUSY:  The system has detected an attempt to reinitialize the mutex
105  *
106  * Alternatively, in case of error the implementation is allowed to
107  * notify it to the system console and then terminate the FRSH
108  * implementation and dependant applications
109  **/
110 int fosa_mutex_init(frsh_mutex_t *mutex, int prioceiling)
111 {
112     if ((prioceiling < fosa_get_priority_min()) ||
113         (prioceiling > fosa_get_priority_max())) {
114         return FOSA_EINVAL;
115     }
116     // Other errors taken care of by OSE.
117     
118     mutex->prio_ceiling             = prioceiling;
119     // As initial value the lowest(!) OSE priority is used.
120     mutex->process_original_prio    = FRSH_HIGHEST_THREAD_PRIORITY;     
121     ose_mutex_init(&mutex->ose_mutex, 0);
122     
123     return 0;    
124 }
125
126 /**
127  * fosa_mutex_destroy()
128  *
129  * Destroy a frsh mutex
130  * 
131  * The mutex pointed to by mutex is destroyed
132  * 
133  * Returns 0 if successful; otherwise it returns an error code:
134  *    EINVAL: the value of mutex is invalid
135  *    EBUSY:  The mutex is in use (is locked)  
136  *
137  * Alternatively, in case of error the implementation is allowed to
138  * notify it to the system console and then terminate the FRSH
139  * implementation and dependant applications
140  **/
141 int fosa_mutex_destroy(frsh_mutex_t *mutex)
142 {
143     ose_mutex_destroy(&mutex->ose_mutex);
144     // Errors taken care of by OSE.
145     return 0;
146 }
147
148 /**
149  * fosa_mutex_set_prioceiling()
150  *
151  * Dynamically set the priority ceiling of a mutex
152  * 
153  * This function locks the mutex (blocking the calling thread if
154  * necessary) and after it is locked it changes its priority ceiling
155  * to the value specified by new_ceiling, and then it unlocks the
156  * mutex. The previous value of the ceiling is returned in
157  * old_ceiling.
158  * 
159  * Returns 0 if successful; otherwise it returns an error code:
160  *     EINVAL: the value of mutex or prioceiling is invalid
161  *
162  * Alternatively, in case of error the implementation is allowed to
163  * notify it to the system console and then terminate the FRSH
164  * implementation and dependant applications
165  **/
166 int fosa_mutex_set_prioceiling
167    (frsh_mutex_t *mutex, int new_ceiling, int *old_ceiling)
168 {
169     if ((new_ceiling < fosa_get_priority_min()) ||
170         (new_ceiling > fosa_get_priority_max())) {
171         return FOSA_EINVAL;
172     }
173     
174     *old_ceiling = mutex->prio_ceiling;
175     
176     ose_mutex_lock(&mutex->ose_mutex);
177     mutex->prio_ceiling = new_ceiling;
178     ose_mutex_unlock(&mutex->ose_mutex);
179     
180     return 0;    
181 }
182     
183 /**
184  * fosa_mutex_get_prioceiling()
185  *
186  * Dynamically get the priority ceiling of a mutex 
187  *
188  * This function copies into the variable pointed to by ceiling the
189  * current priority ceiling of the mutex referenced by mutex
190  * 
191  * Returns 0 if successful; otherwise it returns an error code:
192  *     EINVAL: the value of mutex is invalid
193  *
194  * Alternatively, in case of error the implementation is allowed to
195  * notify it to the system console and then terminate the FRSH
196  * implementation and dependant applications
197  **/
198 int fosa_mutex_get_prioceiling(const frsh_mutex_t *mutex, int *ceiling)
199
200     //if (???) return FOSA_EINVAL; //How to check this?..........................
201
202     *ceiling = mutex->prio_ceiling;
203     
204     return 0;
205 }
206
207 /**
208  * fosa_mutex_lock()
209  *
210  * Lock a mutex
211  * 
212  * This function locks the mutex specified by mutex. If it is already
213  * locked, the calling thread blocks until the mutex becomes
214  * available. The operation returns with the mutex in the locked
215  * state, with the calling thread as its owner.
216  * 
217  * Returns 0 if successful; otherwise it returns an error code:
218  *    EINVAL: the value of mutex is invalid, or the priority of the
219  *            calling thread is higher than the priority ceiling of the mutex
220  *    EDEADLK: the current thread already owns this mutex
221  *
222  * Alternatively, in case of error the implementation is allowed to
223  * notify it to the system console and then terminate the FRSH
224  * implementation and dependant applications
225  **/
226 int fosa_mutex_lock(frsh_mutex_t *mutex)
227 {
228     PROCESS pid = current_process();  
229     OSPRIORITY ose_orig_pri = get_pri(pid);
230     
231     // Mapping of OSE prio to FOSA prio.
232     int original_frsh_prio = fosa_get_priority_max() 
233                              + fosa_get_priority_min() - (int) ose_orig_pri;
234     if (original_frsh_prio > mutex->prio_ceiling) {
235         // This is a step from the ICPP ptotocol, where no error is given.
236         return FOSA_EINVAL;
237     }
238        
239     OSPRIORITY ose_prio_ceiling = (OSPRIORITY) fosa_get_priority_max() 
240                          + fosa_get_priority_min() - mutex->prio_ceiling;
241     set_pri_for(pid, ose_prio_ceiling); 
242     
243     ose_mutex_lock( &(mutex->ose_mutex) );
244     // Change the original priority of mutex after lock is locked.
245     mutex->process_original_prio = ose_orig_pri;
246     // Other errors taken care of by OSE. 
247     return 0;    
248 }
249
250 /**
251  * fosa_mutex_trylock()
252  *
253  * Try locking a mutex
254  *
255  * This function is identical to fosa_mutex_lock() except that if the
256  * mutex is already locked the call returns immediately with an error
257  * indication.
258  *
259  * Returns 0 if successful; otherwise it returns an error code:
260  *    EINVAL: the value of mutex is invalid, or the priority of the
261  *            calling thread is higher than the priority ceiling of the mutex
262  *    EBUSY: the mutex was already locked
263  *
264  * Alternatively, except for EBUSY, in case of error the
265  * implementation is allowed to notify it to the system console and
266  * then terminate the FRSH implementation and dependant applications
267  **/
268 int fosa_mutex_trylock(frsh_mutex_t *mutex)
269 {
270     PROCESS pid = current_process();  
271     OSPRIORITY ose_orig_pri = get_pri(pid);
272     
273     //Mapping of OSE prio to FOSA prio.
274     int original_frsh_prio = fosa_get_priority_max() + fosa_get_priority_min()
275                          - (int) ose_orig_pri;
276     if (original_frsh_prio > mutex->prio_ceiling) {
277         // This is a step from the ICPP ptotocol, where no error is given.
278         return FOSA_EINVAL;
279     }   
280     OSPRIORITY ose_prio_ceiling = (OSPRIORITY) fosa_get_priority_max() 
281                          + fosa_get_priority_min() - mutex->prio_ceiling;
282     set_pri_for(pid, ose_prio_ceiling);
283               
284     int ret_code = ose_mutex_trylock(&mutex->ose_mutex);
285     
286     // Other errors taken care of by OSE. 
287     if (ret_code == 0) {
288         set_pri_for(pid, ose_orig_pri);
289         return EBUSY;
290     } else {
291         mutex->process_original_prio = ose_orig_pri;
292         return 0;
293     }    
294 }
295
296 /**
297  * fosa_mutex_unlock()
298  *
299  * Unlock a mutex
300  * 
301  * This function must be called by the owner of the mutex referenced
302  * by mutex, to unlock it. If there are threads blocked on the mutex
303  * the mutex becomes available and the highest priority thread is
304  * awakened to acquire the mutex.
305  * 
306  * Returns 0 if successful; otherwise it returns an error code:
307  *     EINVAL: the value of mutex is invalid
308  *     EPERM: the calling thread is not the owner of the mutex
309  *
310  * Alternatively, except for EBUSY, in case of error the
311  * implementation is allowed to notify it to the system console and
312  * then terminate the FRSH implementation and dependant applications 
313  **/
314 int fosa_mutex_unlock(frsh_mutex_t *mutex)
315 {
316     // Errors taken care of by OSE.
317     ose_mutex_unlock( &(mutex->ose_mutex) );
318     set_pri_for(current_process(), mutex->process_original_prio);
319         
320     return 0;  
321 }
322
323 /**********************
324  * Condition variables
325  *********************/
326
327 /**
328  * fosa_cond_init()
329  *
330  * Initiatize a condition variable
331  * 
332  * The condition variable referenced by cond is initialized with
333  * the attributes required by the FOSA implementation.
334  *
335  *  Returns 0 if successful; otherwise it returns an error code:
336  *     EAGAIN: the system lacked the necessary resources to create the
337  *             condition variable
338  *     ENOMEM: Insufficient memory exists to initialize the condition variable
339  *     EBUSY:  The system has detected an attempt to reinitialize the 
340  *             condition variable
341  *
342  * Alternatively, in case of error the implementation is allowed to
343  * notify it to the system console and then terminate the FRSH
344  * implementation and dependant applications
345  **/
346 int fosa_cond_init(fosa_cond_t *cond)
347 {
348     cond->pid_queue_length = -1;
349     return 0;
350 }
351
352 /**
353  * fosa_cond_destroy()
354  *
355  * Destroy a condition variable
356  *
357  * The condition variable pointed to by cond is destroyed
358  * 
359  * Returns 0 if successful; otherwise it returns an error code:
360  *     EINVAL: the value of cond is invalid
361  *     EBUSY:  The condition variable is in use (a thread is waiting on it)  
362  *
363  * Alternatively, in case of error the implementation is allowed to
364  * notify it to the system console and then terminate the FRSH
365  * implementation and dependant applications
366  **/
367 int fosa_cond_destroy(fosa_cond_t *cond) 
368 {
369     //With other design a free memory operation could be done here.............
370     return 0;
371 }
372
373 /**
374  * fosa_cond_signal()
375  *
376  * Signal a condition variable
377  *
378  * This call unblocks at least one of the threads that are waiting on
379  * the condition variable referenced by cond. If there are no threads
380  * waiting, the function has no effect
381  *
382  * Returns 0 if successful; otherwise it returns an error code:
383  *     EINVAL: the value of cond is invalid
384  *
385  * Alternatively, in case of error the implementation is allowed to
386  * notify it to the system console and then terminate the FRSH
387  * implementation and dependant applications
388  **/
389 int fosa_cond_signal(fosa_cond_t *cond)
390 {
391     fosa_ose_signal_t *sig;
392     sig = (fosa_ose_signal_t *)alloc(
393             sizeof(fosa_ose_signal_t), FOSA_OSE_CONDVAR_SIGNAL);
394     
395     PROCESS receiver = cond->pid[0];
396     send((union SIGNAL **)&sig, receiver); 
397     
398     cond->pid[cond->pid_queue_length] = (PROCESS) 0;
399     cond->pid_queue_length -=1;
400     int i;
401     for (i = 0; i <= cond->pid_queue_length; ++i) {
402         cond->pid[i] = cond->pid[i+1];
403     }
404     return 0;
405 }
406
407 /**
408  * fosa_cond_broadcast()
409  *
410  * Broadcast a condition variable
411  *
412  * This call unblocks all of the threads that are waiting on the
413  * condition variable referenced by cond. If there are no threads
414  * waiting, the function has no effect.
415  *
416  * Returns 0 if successful; otherwise it returns an error code:
417  *     EINVAL: the value of cond is invalid
418  *
419  * Alternatively, in case of error the implementation is allowed to
420  * notify it to the system console and then terminate the FRSH
421  * implementation and dependant applications
422  **/
423 int fosa_cond_broadcast(fosa_cond_t *cond)
424 {
425     fosa_ose_signal_t* sig[cond->pid_queue_length];
426     int i;
427     PROCESS receiver;    
428     
429     for (i = 0; i <= cond->pid_queue_length; ++i) {
430         sig[i] = (fosa_ose_signal_t *)alloc(
431                sizeof(fosa_ose_signal_t), FOSA_OSE_CONDVAR_SIGNAL);
432         receiver = cond->pid[i];
433         send((union SIGNAL **)&sig[i], receiver); 
434         cond->pid[i] = (PROCESS) 0;
435     }        
436     cond->pid_queue_length = -1;
437     return 0;
438 }
439
440 /**
441  * fosa_cond_wait()
442  *
443  * Wait at a condition variable
444  *
445  * This call is used to block on the condition variable referenced by
446  * cond. It shall be called with the mutex referenced by mutex
447  * locked. The function releases the mutex and blocks the calling
448  * thread until the condition is signalled by some other thread and
449  * the calling thread is awakened. Then it locks the mutex and
450  * returns with the mutex locked by the calling thread.
451  *
452  * Returns 0 if successful; otherwise it returns an error code:
453  *    EINVAL: the value of cond or mutex is invalid, or different
454  *            mutexes were used for concurrent wait operations on cond, or
455  *            the mutex was not owned by the calling thread
456  *
457  * Alternatively, in case of error the implementation is allowed to
458  * notify it to the system console and then terminate the FRSH
459  * implementation and dependant applications
460  **/
461 int fosa_cond_wait(fosa_cond_t *cond, frsh_mutex_t *mutex)
462 {
463     fosa_mutex_unlock(mutex);
464     
465     cond->pid_queue_length += 1;
466     cond->pid[cond->pid_queue_length] = current_process();
467     
468     static const SIGSELECT condvar_signal[] = {1,FOSA_OSE_CONDVAR_SIGNAL};
469     union SIGNAL *sig;
470     
471     sig = receive(condvar_signal);
472     
473     fosa_mutex_lock(mutex);
474     return 0;
475 }
476
477 /**
478  * fosa_cond_timedwait()
479  *
480  * Wait at a condition variable, with a timeout
481  * 
482  * This function is equal to fosa_cond_wait(), except that the maximum
483  * wait time is limited to the absolute time referenced by abstime, as
484  * measured by the FOSA_CLOCK_REALTIME clock.
485  *
486  * Returns 0 if successful; otherwise it returns an error code:
487  *     EINVAL: the value of cond or mutex or abstime is invalid, or different
488  *             mutexes were used for concurrent wait operations on cond, or
489  *             the mutex was not owned by the calling thread
490  *     ETIMEDOUT: the timeout expired
491  *
492  * Alternatively, except for ETIMEDOUT, in case of error the
493  * implementation is allowed to notify it to the system console and
494  * then terminate the FRSH implementation and dependant applications
495  **/
496 int fosa_cond_timedwait(fosa_cond_t *cond, frsh_mutex_t *mutex, 
497         const struct timespec abstime)
498 {
499     fosa_mutex_unlock(mutex);
500     
501     cond->pid_queue_length += 1;
502     cond->pid[cond->pid_queue_length] = current_process();
503     
504     static const SIGSELECT condvar_signal[] = {1,FOSA_OSE_CONDVAR_SIGNAL};
505     union SIGNAL *sig;
506     
507     OSTIME millisec = abstime.tv_sec * 1000 + abstime.tv_nsec / 1000;
508     
509     sig = receive_w_tmo(millisec, condvar_signal);
510         
511     if(sig == NIL) return ETIMEDOUT;
512     
513     fosa_mutex_lock(mutex);
514     return 0;
515 }
516
517 /*@}*/ 
518  
519
520