source: mainline/uspace/lib/c/generic/thread/fibril_synch.c@ d5409da

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d5409da was d5409da, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 21 months ago

C++: mutex::init should be constexpr

  • Property mode set to 100644
File size: 17.8 KB
Line 
1/*
2 * Copyright (c) 2009 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <fibril_synch.h>
36#include <fibril.h>
37#include <async.h>
38#include <adt/list.h>
39#include <time.h>
40#include <errno.h>
41#include <assert.h>
42#include <stacktrace.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <io/kio.h>
46#include <mem.h>
47#include <context.h>
48
49#include "../private/async.h"
50#include "../private/fibril.h"
51#include "../private/futex.h"
52
53errno_t fibril_rmutex_initialize(fibril_rmutex_t *m)
54{
55 return futex_initialize(&m->futex, 1);
56}
57
58void fibril_rmutex_destroy(fibril_rmutex_t *m)
59{
60 futex_destroy(&m->futex);
61}
62
63/**
64 * Lock restricted mutex.
65 * When a restricted mutex is locked, the fibril may not sleep or create new
66 * threads. Any attempt to do so will abort the program.
67 */
68void fibril_rmutex_lock(fibril_rmutex_t *m)
69{
70 futex_lock(&m->futex);
71 fibril_self()->rmutex_locks++;
72}
73
74bool fibril_rmutex_trylock(fibril_rmutex_t *m)
75{
76 if (futex_trylock(&m->futex)) {
77 fibril_self()->rmutex_locks++;
78 return true;
79 } else {
80 return false;
81 }
82}
83
84void fibril_rmutex_unlock(fibril_rmutex_t *m)
85{
86 fibril_self()->rmutex_locks--;
87 futex_unlock(&m->futex);
88}
89
90static fibril_local bool deadlocked = false;
91
92static futex_t fibril_synch_futex;
93
94void __fibril_synch_init(void)
95{
96 if (futex_initialize(&fibril_synch_futex, 1) != EOK)
97 abort();
98}
99
100void __fibril_synch_fini(void)
101{
102 futex_destroy(&fibril_synch_futex);
103}
104
105typedef struct {
106 link_t link;
107 fibril_event_t event;
108 fibril_mutex_t *mutex;
109 fid_t fid;
110} awaiter_t;
111
112#define AWAITER_INIT { .fid = fibril_get_id() }
113
114static void print_deadlock(fibril_owner_info_t *oi)
115{
116 // FIXME: Print to stderr.
117
118 fibril_t *f = (fibril_t *) fibril_get_id();
119
120 if (deadlocked) {
121 kio_printf("Deadlock detected while printing deadlock. Aborting.\n");
122 abort();
123 }
124 deadlocked = true;
125
126 printf("Deadlock detected.\n");
127 stacktrace_print();
128
129 printf("Fibril %p waits for primitive %p.\n", f, oi);
130
131 while (oi && oi->owned_by) {
132 printf("Primitive %p is owned by fibril %p.\n",
133 oi, oi->owned_by);
134 if (oi->owned_by == f)
135 break;
136 stacktrace_print_fp_pc(
137 context_get_fp(&oi->owned_by->ctx),
138 context_get_pc(&oi->owned_by->ctx));
139 printf("Fibril %p waits for primitive %p.\n",
140 oi->owned_by, oi->owned_by->waits_for);
141 oi = oi->owned_by->waits_for;
142 }
143}
144
145static void check_fibril_for_deadlock(fibril_owner_info_t *oi, fibril_t *fib)
146{
147 futex_assert_is_locked(&fibril_synch_futex);
148
149 while (oi && oi->owned_by) {
150 if (oi->owned_by == fib) {
151 futex_unlock(&fibril_synch_futex);
152 print_deadlock(oi);
153 abort();
154 }
155 oi = oi->owned_by->waits_for;
156 }
157}
158
159static void check_for_deadlock(fibril_owner_info_t *oi)
160{
161 check_fibril_for_deadlock(oi, fibril_self());
162}
163
164void fibril_mutex_lock(fibril_mutex_t *fm)
165{
166 fibril_t *f = (fibril_t *) fibril_get_id();
167
168 futex_lock(&fibril_synch_futex);
169
170 if (fm->counter-- > 0) {
171 fm->oi.owned_by = f;
172 futex_unlock(&fibril_synch_futex);
173 return;
174 }
175
176 awaiter_t wdata = AWAITER_INIT;
177 list_append(&wdata.link, &fm->waiters);
178 check_for_deadlock(&fm->oi);
179 f->waits_for = &fm->oi;
180
181 futex_unlock(&fibril_synch_futex);
182
183 fibril_wait_for(&wdata.event);
184}
185
186bool fibril_mutex_trylock(fibril_mutex_t *fm)
187{
188 bool locked = false;
189
190 futex_lock(&fibril_synch_futex);
191 if (fm->counter > 0) {
192 fm->counter--;
193 fm->oi.owned_by = (fibril_t *) fibril_get_id();
194 locked = true;
195 }
196 futex_unlock(&fibril_synch_futex);
197
198 return locked;
199}
200
201static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
202{
203 assert(fm->oi.owned_by == (fibril_t *) fibril_get_id());
204
205 if (fm->counter++ < 0) {
206 awaiter_t *wdp = list_pop(&fm->waiters, awaiter_t, link);
207 assert(wdp);
208
209 fibril_t *f = (fibril_t *) wdp->fid;
210 fm->oi.owned_by = f;
211 f->waits_for = NULL;
212
213 fibril_notify(&wdp->event);
214 } else {
215 fm->oi.owned_by = NULL;
216 }
217}
218
219void fibril_mutex_unlock(fibril_mutex_t *fm)
220{
221 futex_lock(&fibril_synch_futex);
222 _fibril_mutex_unlock_unsafe(fm);
223 futex_unlock(&fibril_synch_futex);
224}
225
226bool fibril_mutex_is_locked(fibril_mutex_t *fm)
227{
228 futex_lock(&fibril_synch_futex);
229 bool locked = (fm->oi.owned_by == (fibril_t *) fibril_get_id());
230 futex_unlock(&fibril_synch_futex);
231 return locked;
232}
233
234void fibril_rwlock_initialize(fibril_rwlock_t *frw)
235{
236 frw->oi.owned_by = NULL;
237 frw->writers = 0;
238 frw->readers = 0;
239 list_initialize(&frw->waiters);
240}
241
242void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
243{
244 fibril_t *f = (fibril_t *) fibril_get_id();
245
246 futex_lock(&fibril_synch_futex);
247
248 if (!frw->writers) {
249 /* Consider the first reader the owner. */
250 if (frw->readers++ == 0)
251 frw->oi.owned_by = f;
252 futex_unlock(&fibril_synch_futex);
253 return;
254 }
255
256 f->is_writer = false;
257
258 awaiter_t wdata = AWAITER_INIT;
259 list_append(&wdata.link, &frw->waiters);
260 check_for_deadlock(&frw->oi);
261 f->waits_for = &frw->oi;
262
263 futex_unlock(&fibril_synch_futex);
264
265 fibril_wait_for(&wdata.event);
266}
267
268void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
269{
270 fibril_t *f = (fibril_t *) fibril_get_id();
271
272 futex_lock(&fibril_synch_futex);
273
274 if (!frw->writers && !frw->readers) {
275 frw->oi.owned_by = f;
276 frw->writers++;
277 futex_unlock(&fibril_synch_futex);
278 return;
279 }
280
281 f->is_writer = true;
282
283 awaiter_t wdata = AWAITER_INIT;
284 list_append(&wdata.link, &frw->waiters);
285 check_for_deadlock(&frw->oi);
286 f->waits_for = &frw->oi;
287
288 futex_unlock(&fibril_synch_futex);
289
290 fibril_wait_for(&wdata.event);
291}
292
293static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
294{
295 if (frw->readers) {
296 if (--frw->readers) {
297 if (frw->oi.owned_by == (fibril_t *) fibril_get_id()) {
298 /*
299 * If this reader fibril was considered the
300 * owner of this rwlock, clear the ownership
301 * information even if there are still more
302 * readers.
303 *
304 * This is the limitation of the detection
305 * mechanism rooted in the fact that tracking
306 * all readers would require dynamically
307 * allocated memory for keeping linkage info.
308 */
309 frw->oi.owned_by = NULL;
310 }
311
312 return;
313 }
314 } else {
315 frw->writers--;
316 }
317
318 assert(!frw->readers && !frw->writers);
319
320 frw->oi.owned_by = NULL;
321
322 while (!list_empty(&frw->waiters)) {
323 link_t *tmp = list_first(&frw->waiters);
324 awaiter_t *wdp;
325 fibril_t *f;
326
327 wdp = list_get_instance(tmp, awaiter_t, link);
328 f = (fibril_t *) wdp->fid;
329
330 if (f->is_writer) {
331 if (frw->readers)
332 break;
333 frw->writers++;
334 } else {
335 frw->readers++;
336 }
337
338 f->waits_for = NULL;
339 list_remove(&wdp->link);
340 frw->oi.owned_by = f;
341 fibril_notify(&wdp->event);
342
343 if (frw->writers)
344 break;
345 }
346}
347
348void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
349{
350 futex_lock(&fibril_synch_futex);
351 assert(frw->readers > 0);
352 _fibril_rwlock_common_unlock(frw);
353 futex_unlock(&fibril_synch_futex);
354}
355
356void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
357{
358 futex_lock(&fibril_synch_futex);
359 assert(frw->writers == 1);
360 assert(frw->oi.owned_by == fibril_self());
361 _fibril_rwlock_common_unlock(frw);
362 futex_unlock(&fibril_synch_futex);
363}
364
365bool fibril_rwlock_is_read_locked(fibril_rwlock_t *frw)
366{
367 futex_lock(&fibril_synch_futex);
368 bool locked = (frw->readers > 0);
369 futex_unlock(&fibril_synch_futex);
370 return locked;
371}
372
373bool fibril_rwlock_is_write_locked(fibril_rwlock_t *frw)
374{
375 futex_lock(&fibril_synch_futex);
376 assert(frw->writers <= 1);
377 bool locked = (frw->writers > 0) && (frw->oi.owned_by == fibril_self());
378 futex_unlock(&fibril_synch_futex);
379 return locked;
380}
381
382bool fibril_rwlock_is_locked(fibril_rwlock_t *frw)
383{
384 return fibril_rwlock_is_read_locked(frw) ||
385 fibril_rwlock_is_write_locked(frw);
386}
387
388void fibril_condvar_initialize(fibril_condvar_t *fcv)
389{
390 list_initialize(&fcv->waiters);
391}
392
393/**
394 * FIXME: If `timeout` is negative, the function returns ETIMEOUT immediately,
395 * and if `timeout` is 0, the wait never times out.
396 * This is not consistent with other similar APIs.
397 */
398errno_t
399fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
400 usec_t timeout)
401{
402 assert(fibril_mutex_is_locked(fm));
403
404 if (timeout < 0)
405 return ETIMEOUT;
406
407 awaiter_t wdata = AWAITER_INIT;
408 wdata.mutex = fm;
409
410 struct timespec ts;
411 struct timespec *expires = NULL;
412 if (timeout) {
413 getuptime(&ts);
414 ts_add_diff(&ts, USEC2NSEC(timeout));
415 expires = &ts;
416 }
417
418 futex_lock(&fibril_synch_futex);
419 _fibril_mutex_unlock_unsafe(fm);
420 list_append(&wdata.link, &fcv->waiters);
421 futex_unlock(&fibril_synch_futex);
422
423 (void) fibril_wait_timeout(&wdata.event, expires);
424
425 futex_lock(&fibril_synch_futex);
426 bool timed_out = link_in_use(&wdata.link);
427 list_remove(&wdata.link);
428 futex_unlock(&fibril_synch_futex);
429
430 fibril_mutex_lock(fm);
431
432 return timed_out ? ETIMEOUT : EOK;
433}
434
435void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
436{
437 (void) fibril_condvar_wait_timeout(fcv, fm, 0);
438}
439
440void fibril_condvar_signal(fibril_condvar_t *fcv)
441{
442 futex_lock(&fibril_synch_futex);
443
444 awaiter_t *w = list_pop(&fcv->waiters, awaiter_t, link);
445 if (w != NULL)
446 fibril_notify(&w->event);
447
448 futex_unlock(&fibril_synch_futex);
449}
450
451void fibril_condvar_broadcast(fibril_condvar_t *fcv)
452{
453 futex_lock(&fibril_synch_futex);
454
455 awaiter_t *w;
456 while ((w = list_pop(&fcv->waiters, awaiter_t, link)))
457 fibril_notify(&w->event);
458
459 futex_unlock(&fibril_synch_futex);
460}
461
462/** Timer fibril.
463 *
464 * @param arg Timer
465 */
466static errno_t fibril_timer_func(void *arg)
467{
468 fibril_timer_t *timer = (fibril_timer_t *) arg;
469 errno_t rc;
470
471 fibril_mutex_lock(timer->lockp);
472
473 while (timer->state != fts_cleanup) {
474 switch (timer->state) {
475 case fts_not_set:
476 case fts_fired:
477 fibril_condvar_wait(&timer->cv, timer->lockp);
478 break;
479 case fts_active:
480 rc = fibril_condvar_wait_timeout(&timer->cv,
481 timer->lockp, timer->delay);
482 if (rc == ETIMEOUT && timer->state == fts_active) {
483 timer->state = fts_fired;
484 timer->handler_fid = fibril_get_id();
485 fibril_mutex_unlock(timer->lockp);
486 timer->fun(timer->arg);
487 fibril_mutex_lock(timer->lockp);
488 timer->handler_fid = 0;
489 }
490 break;
491 case fts_cleanup:
492 case fts_clean:
493 assert(false);
494 break;
495 }
496 }
497
498 /* Acknowledge timer fibril has finished cleanup. */
499 timer->state = fts_clean;
500 fibril_condvar_broadcast(&timer->cv);
501 fibril_mutex_unlock(timer->lockp);
502
503 return 0;
504}
505
506/** Create new timer.
507 *
508 * @return New timer on success, @c NULL if out of memory.
509 */
510fibril_timer_t *fibril_timer_create(fibril_mutex_t *lock)
511{
512 fid_t fid;
513 fibril_timer_t *timer;
514
515 timer = calloc(1, sizeof(fibril_timer_t));
516 if (timer == NULL)
517 return NULL;
518
519 fid = fibril_create(fibril_timer_func, (void *) timer);
520 if (fid == 0) {
521 free(timer);
522 return NULL;
523 }
524
525 fibril_mutex_initialize(&timer->lock);
526 fibril_condvar_initialize(&timer->cv);
527
528 timer->fibril = fid;
529 timer->state = fts_not_set;
530 timer->lockp = (lock != NULL) ? lock : &timer->lock;
531
532 fibril_add_ready(fid);
533 return timer;
534}
535
536/** Destroy timer.
537 *
538 * @param timer Timer, must not be active or accessed by other threads.
539 */
540void fibril_timer_destroy(fibril_timer_t *timer)
541{
542 fibril_mutex_lock(timer->lockp);
543 assert(timer->state == fts_not_set || timer->state == fts_fired);
544
545 /* Request timer fibril to terminate. */
546 timer->state = fts_cleanup;
547 fibril_condvar_broadcast(&timer->cv);
548
549 /* Wait for timer fibril to terminate */
550 while (timer->state != fts_clean)
551 fibril_condvar_wait(&timer->cv, timer->lockp);
552 fibril_mutex_unlock(timer->lockp);
553
554 free(timer);
555}
556
557/** Set timer.
558 *
559 * Set timer to execute a callback function after the specified
560 * interval.
561 *
562 * @param timer Timer
563 * @param delay Delay in microseconds
564 * @param fun Callback function
565 * @param arg Argument for @a fun
566 */
567void fibril_timer_set(fibril_timer_t *timer, usec_t delay,
568 fibril_timer_fun_t fun, void *arg)
569{
570 fibril_mutex_lock(timer->lockp);
571 fibril_timer_set_locked(timer, delay, fun, arg);
572 fibril_mutex_unlock(timer->lockp);
573}
574
575/** Set locked timer.
576 *
577 * Set timer to execute a callback function after the specified
578 * interval. Must be called when the timer is locked.
579 *
580 * @param timer Timer
581 * @param delay Delay in microseconds
582 * @param fun Callback function
583 * @param arg Argument for @a fun
584 */
585void fibril_timer_set_locked(fibril_timer_t *timer, usec_t delay,
586 fibril_timer_fun_t fun, void *arg)
587{
588 assert(fibril_mutex_is_locked(timer->lockp));
589 assert(timer->state == fts_not_set || timer->state == fts_fired);
590 timer->state = fts_active;
591 timer->delay = delay;
592 timer->fun = fun;
593 timer->arg = arg;
594 fibril_condvar_broadcast(&timer->cv);
595}
596
597/** Clear timer.
598 *
599 * Clears (cancels) timer and returns last state of the timer.
600 * This can be one of:
601 * - fts_not_set If the timer has not been set or has been cleared
602 * - fts_active Timer was set but did not fire
603 * - fts_fired Timer fired
604 *
605 * @param timer Timer
606 * @return Last timer state
607 */
608fibril_timer_state_t fibril_timer_clear(fibril_timer_t *timer)
609{
610 fibril_timer_state_t old_state;
611
612 fibril_mutex_lock(timer->lockp);
613 old_state = fibril_timer_clear_locked(timer);
614 fibril_mutex_unlock(timer->lockp);
615
616 return old_state;
617}
618
619/** Clear locked timer.
620 *
621 * Clears (cancels) timer and returns last state of the timer.
622 * This can be one of:
623 * - fts_not_set If the timer has not been set or has been cleared
624 * - fts_active Timer was set but did not fire
625 * - fts_fired Timer fired
626 * Must be called when the timer is locked.
627 *
628 * @param timer Timer
629 * @return Last timer state
630 */
631fibril_timer_state_t fibril_timer_clear_locked(fibril_timer_t *timer)
632{
633 fibril_timer_state_t old_state;
634
635 assert(fibril_mutex_is_locked(timer->lockp));
636
637 while (timer->handler_fid != 0) {
638 if (timer->handler_fid == fibril_get_id()) {
639 printf("Deadlock detected.\n");
640 stacktrace_print();
641 printf("Fibril %p is trying to clear timer %p from "
642 "inside its handler %p.\n",
643 fibril_get_id(), timer, timer->fun);
644 abort();
645 }
646
647 fibril_condvar_wait(&timer->cv, timer->lockp);
648 }
649
650 old_state = timer->state;
651 timer->state = fts_not_set;
652
653 timer->delay = 0;
654 timer->fun = NULL;
655 timer->arg = NULL;
656 fibril_condvar_broadcast(&timer->cv);
657
658 return old_state;
659}
660
661/**
662 * Initialize a semaphore with initial count set to the provided value.
663 *
664 * @param sem Semaphore to initialize.
665 * @param count Initial count. Must not be negative.
666 */
667void fibril_semaphore_initialize(fibril_semaphore_t *sem, long count)
668{
669 /*
670 * Negative count denotes the length of waitlist,
671 * so it makes no sense as an initial value.
672 */
673 assert(count >= 0);
674 sem->closed = false;
675 sem->count = count;
676 list_initialize(&sem->waiters);
677}
678
679/**
680 * Produce one token.
681 * If there are fibrils waiting for tokens, this operation satisfies
682 * exactly one waiting `fibril_semaphore_down()`.
683 * This operation never blocks the fibril.
684 *
685 * @param sem Semaphore to use.
686 */
687void fibril_semaphore_up(fibril_semaphore_t *sem)
688{
689 futex_lock(&fibril_synch_futex);
690
691 if (sem->closed) {
692 futex_unlock(&fibril_synch_futex);
693 return;
694 }
695
696 sem->count++;
697
698 if (sem->count <= 0) {
699 awaiter_t *w = list_pop(&sem->waiters, awaiter_t, link);
700 assert(w);
701 fibril_notify(&w->event);
702 }
703
704 futex_unlock(&fibril_synch_futex);
705}
706
707/**
708 * Consume one token.
709 * If there are no available tokens (count <= 0), this operation blocks until
710 * another fibril produces a token using `fibril_semaphore_up()`.
711 *
712 * @param sem Semaphore to use.
713 */
714void fibril_semaphore_down(fibril_semaphore_t *sem)
715{
716 futex_lock(&fibril_synch_futex);
717
718 if (sem->closed) {
719 futex_unlock(&fibril_synch_futex);
720 return;
721 }
722
723 sem->count--;
724
725 if (sem->count >= 0) {
726 futex_unlock(&fibril_synch_futex);
727 return;
728 }
729
730 awaiter_t wdata = AWAITER_INIT;
731 list_append(&wdata.link, &sem->waiters);
732
733 futex_unlock(&fibril_synch_futex);
734
735 fibril_wait_for(&wdata.event);
736}
737
738errno_t fibril_semaphore_down_timeout(fibril_semaphore_t *sem, usec_t timeout)
739{
740 if (timeout < 0)
741 return ETIMEOUT;
742
743 futex_lock(&fibril_synch_futex);
744 if (sem->closed) {
745 futex_unlock(&fibril_synch_futex);
746 return EOK;
747 }
748
749 sem->count--;
750
751 if (sem->count >= 0) {
752 futex_unlock(&fibril_synch_futex);
753 return EOK;
754 }
755
756 awaiter_t wdata = AWAITER_INIT;
757 list_append(&wdata.link, &sem->waiters);
758
759 futex_unlock(&fibril_synch_futex);
760
761 struct timespec ts;
762 struct timespec *expires = NULL;
763 if (timeout) {
764 getuptime(&ts);
765 ts_add_diff(&ts, USEC2NSEC(timeout));
766 expires = &ts;
767 }
768
769 errno_t rc = fibril_wait_timeout(&wdata.event, expires);
770 if (rc == EOK)
771 return EOK;
772
773 futex_lock(&fibril_synch_futex);
774 if (!link_in_use(&wdata.link)) {
775 futex_unlock(&fibril_synch_futex);
776 return EOK;
777 }
778
779 list_remove(&wdata.link);
780 sem->count++;
781 futex_unlock(&fibril_synch_futex);
782
783 return rc;
784}
785
786/**
787 * Close the semaphore.
788 * All future down() operations return instantly.
789 */
790void fibril_semaphore_close(fibril_semaphore_t *sem)
791{
792 futex_lock(&fibril_synch_futex);
793 sem->closed = true;
794 awaiter_t *w;
795
796 while ((w = list_pop(&sem->waiters, awaiter_t, link)))
797 fibril_notify(&w->event);
798
799 futex_unlock(&fibril_synch_futex);
800}
801
802/** @}
803 */
Note: See TracBrowser for help on using the repository browser.