1 // -----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2007 by the FRESCOR consortium:
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
11 // Thales Communication S.A. FRANCE
12 // Visual Tools S.A. SPAIN
13 // Rapita Systems Ltd UK
16 // See http://www.frescor.org
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
23 // All rights reserved.
25 // Redistribution and use in source and binary forms, with or
26 // without modification, are permitted provided that the
27 // following conditions are met:
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.
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 // // /******/ //////// // //
67 // FOSA(Frescor Operating System Adaptation layer)
68 //================================================
72 #include "frsh_configuration_parameters.h"
75 #include "fosa_ose_implementation_specific.h"
78 * @defgroup mutexesandcondvars Mutexes and Condvars
81 * This module defines the types and functions to abstract mutexes and
82 * conditional variables for the FRSH implementation.
87 /*******************************************************
88 * Mutexes with priority ceiling
89 ******************************************************/
94 * Initialize a frsh mutex
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.
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
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
110 int fosa_mutex_init(frsh_mutex_t *mutex, int prioceiling)
112 if ((prioceiling < fosa_get_priority_min()) ||
113 (prioceiling > fosa_get_priority_max())) {
116 // Other errors taken care of by OSE.
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);
127 * fosa_mutex_destroy()
129 * Destroy a frsh mutex
131 * The mutex pointed to by mutex is destroyed
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)
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
141 int fosa_mutex_destroy(frsh_mutex_t *mutex)
143 ose_mutex_destroy(&mutex->ose_mutex);
144 // Errors taken care of by OSE.
149 * fosa_mutex_set_prioceiling()
151 * Dynamically set the priority ceiling of a mutex
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
159 * Returns 0 if successful; otherwise it returns an error code:
160 * EINVAL: the value of mutex or prioceiling is invalid
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
166 int fosa_mutex_set_prioceiling
167 (frsh_mutex_t *mutex, int new_ceiling, int *old_ceiling)
169 if ((new_ceiling < fosa_get_priority_min()) ||
170 (new_ceiling > fosa_get_priority_max())) {
174 *old_ceiling = mutex->prio_ceiling;
176 ose_mutex_lock(&mutex->ose_mutex);
177 mutex->prio_ceiling = new_ceiling;
178 ose_mutex_unlock(&mutex->ose_mutex);
184 * fosa_mutex_get_prioceiling()
186 * Dynamically get the priority ceiling of a mutex
188 * This function copies into the variable pointed to by ceiling the
189 * current priority ceiling of the mutex referenced by mutex
191 * Returns 0 if successful; otherwise it returns an error code:
192 * EINVAL: the value of mutex is invalid
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
198 int fosa_mutex_get_prioceiling(const frsh_mutex_t *mutex, int *ceiling)
200 //if (???) return FOSA_EINVAL; //How to check this?..........................
202 *ceiling = mutex->prio_ceiling;
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.
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
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
226 int fosa_mutex_lock(frsh_mutex_t *mutex)
228 PROCESS pid = current_process();
229 OSPRIORITY ose_orig_pri = get_pri(pid);
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.
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);
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.
251 * fosa_mutex_trylock()
253 * Try locking a mutex
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
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
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
268 int fosa_mutex_trylock(frsh_mutex_t *mutex)
270 PROCESS pid = current_process();
271 OSPRIORITY ose_orig_pri = get_pri(pid);
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.
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);
284 int ret_code = ose_mutex_trylock(&mutex->ose_mutex);
286 // Other errors taken care of by OSE.
288 set_pri_for(pid, ose_orig_pri);
291 mutex->process_original_prio = ose_orig_pri;
297 * fosa_mutex_unlock()
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.
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
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
314 int fosa_mutex_unlock(frsh_mutex_t *mutex)
316 // Errors taken care of by OSE.
317 ose_mutex_unlock( &(mutex->ose_mutex) );
318 set_pri_for(current_process(), mutex->process_original_prio);
323 /**********************
324 * Condition variables
325 *********************/
330 * Initiatize a condition variable
332 * The condition variable referenced by cond is initialized with
333 * the attributes required by the FOSA implementation.
335 * Returns 0 if successful; otherwise it returns an error code:
336 * EAGAIN: the system lacked the necessary resources to create the
338 * ENOMEM: Insufficient memory exists to initialize the condition variable
339 * EBUSY: The system has detected an attempt to reinitialize the
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
346 int fosa_cond_init(fosa_cond_t *cond)
348 cond->pid_queue_length = -1;
353 * fosa_cond_destroy()
355 * Destroy a condition variable
357 * The condition variable pointed to by cond is destroyed
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)
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
367 int fosa_cond_destroy(fosa_cond_t *cond)
369 //With other design a free memory operation could be done here.............
376 * Signal a condition variable
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
382 * Returns 0 if successful; otherwise it returns an error code:
383 * EINVAL: the value of cond is invalid
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
389 int fosa_cond_signal(fosa_cond_t *cond)
391 fosa_ose_signal_t *sig;
392 sig = (fosa_ose_signal_t *)alloc(
393 sizeof(fosa_ose_signal_t), FOSA_OSE_CONDVAR_SIGNAL);
395 PROCESS receiver = cond->pid[0];
396 send((union SIGNAL **)&sig, receiver);
398 cond->pid[cond->pid_queue_length] = (PROCESS) 0;
399 cond->pid_queue_length -=1;
401 for (i = 0; i <= cond->pid_queue_length; ++i) {
402 cond->pid[i] = cond->pid[i+1];
408 * fosa_cond_broadcast()
410 * Broadcast a condition variable
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.
416 * Returns 0 if successful; otherwise it returns an error code:
417 * EINVAL: the value of cond is invalid
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
423 int fosa_cond_broadcast(fosa_cond_t *cond)
425 fosa_ose_signal_t* sig[cond->pid_queue_length];
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;
436 cond->pid_queue_length = -1;
443 * Wait at a condition variable
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.
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
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
461 int fosa_cond_wait(fosa_cond_t *cond, frsh_mutex_t *mutex)
463 fosa_mutex_unlock(mutex);
465 cond->pid_queue_length += 1;
466 cond->pid[cond->pid_queue_length] = current_process();
468 static const SIGSELECT condvar_signal[] = {1,FOSA_OSE_CONDVAR_SIGNAL};
471 sig = receive(condvar_signal);
473 fosa_mutex_lock(mutex);
478 * fosa_cond_timedwait()
480 * Wait at a condition variable, with a timeout
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.
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
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
496 int fosa_cond_timedwait(fosa_cond_t *cond, frsh_mutex_t *mutex,
497 const struct timespec abstime)
499 fosa_mutex_unlock(mutex);
501 cond->pid_queue_length += 1;
502 cond->pid[cond->pid_queue_length] = current_process();
504 static const SIGSELECT condvar_signal[] = {1,FOSA_OSE_CONDVAR_SIGNAL};
507 OSTIME millisec = abstime.tv_sec * 1000 + abstime.tv_nsec / 1000;
509 sig = receive_w_tmo(millisec, condvar_signal);
511 if(sig == NIL) return ETIMEDOUT;
513 fosa_mutex_lock(mutex);