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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0b8fad2 was 25f6bddb, checked in by Jakub Jermar <jakub@…>, 7 years ago

Deallocate waitq's used by the loader

  • Property mode set to 100644
File size: 18.0 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_initialize(fibril_mutex_t *fm)
165{
166 fm->oi.owned_by = NULL;
167 fm->counter = 1;
168 list_initialize(&fm->waiters);
169}
170
171void fibril_mutex_lock(fibril_mutex_t *fm)
172{
173 fibril_t *f = (fibril_t *) fibril_get_id();
174
175 futex_lock(&fibril_synch_futex);
176
177 if (fm->counter-- > 0) {
178 fm->oi.owned_by = f;
179 futex_unlock(&fibril_synch_futex);
180 return;
181 }
182
183 awaiter_t wdata = AWAITER_INIT;
184 list_append(&wdata.link, &fm->waiters);
185 check_for_deadlock(&fm->oi);
186 f->waits_for = &fm->oi;
187
188 futex_unlock(&fibril_synch_futex);
189
190 fibril_wait_for(&wdata.event);
191}
192
193bool fibril_mutex_trylock(fibril_mutex_t *fm)
194{
195 bool locked = false;
196
197 futex_lock(&fibril_synch_futex);
198 if (fm->counter > 0) {
199 fm->counter--;
200 fm->oi.owned_by = (fibril_t *) fibril_get_id();
201 locked = true;
202 }
203 futex_unlock(&fibril_synch_futex);
204
205 return locked;
206}
207
208static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
209{
210 assert(fm->oi.owned_by == (fibril_t *) fibril_get_id());
211
212 if (fm->counter++ < 0) {
213 awaiter_t *wdp = list_pop(&fm->waiters, awaiter_t, link);
214 assert(wdp);
215
216 fibril_t *f = (fibril_t *) wdp->fid;
217 fm->oi.owned_by = f;
218 f->waits_for = NULL;
219
220 fibril_notify(&wdp->event);
221 } else {
222 fm->oi.owned_by = NULL;
223 }
224}
225
226void fibril_mutex_unlock(fibril_mutex_t *fm)
227{
228 futex_lock(&fibril_synch_futex);
229 _fibril_mutex_unlock_unsafe(fm);
230 futex_unlock(&fibril_synch_futex);
231}
232
233bool fibril_mutex_is_locked(fibril_mutex_t *fm)
234{
235 futex_lock(&fibril_synch_futex);
236 bool locked = (fm->oi.owned_by == (fibril_t *) fibril_get_id());
237 futex_unlock(&fibril_synch_futex);
238 return locked;
239}
240
241void fibril_rwlock_initialize(fibril_rwlock_t *frw)
242{
243 frw->oi.owned_by = NULL;
244 frw->writers = 0;
245 frw->readers = 0;
246 list_initialize(&frw->waiters);
247}
248
249void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
250{
251 fibril_t *f = (fibril_t *) fibril_get_id();
252
253 futex_lock(&fibril_synch_futex);
254
255 if (!frw->writers) {
256 /* Consider the first reader the owner. */
257 if (frw->readers++ == 0)
258 frw->oi.owned_by = f;
259 futex_unlock(&fibril_synch_futex);
260 return;
261 }
262
263 f->is_writer = false;
264
265 awaiter_t wdata = AWAITER_INIT;
266 list_append(&wdata.link, &frw->waiters);
267 check_for_deadlock(&frw->oi);
268 f->waits_for = &frw->oi;
269
270 futex_unlock(&fibril_synch_futex);
271
272 fibril_wait_for(&wdata.event);
273}
274
275void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
276{
277 fibril_t *f = (fibril_t *) fibril_get_id();
278
279 futex_lock(&fibril_synch_futex);
280
281 if (!frw->writers && !frw->readers) {
282 frw->oi.owned_by = f;
283 frw->writers++;
284 futex_unlock(&fibril_synch_futex);
285 return;
286 }
287
288 f->is_writer = true;
289
290 awaiter_t wdata = AWAITER_INIT;
291 list_append(&wdata.link, &frw->waiters);
292 check_for_deadlock(&frw->oi);
293 f->waits_for = &frw->oi;
294
295 futex_unlock(&fibril_synch_futex);
296
297 fibril_wait_for(&wdata.event);
298}
299
300static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
301{
302 if (frw->readers) {
303 if (--frw->readers) {
304 if (frw->oi.owned_by == (fibril_t *) fibril_get_id()) {
305 /*
306 * If this reader fibril was considered the
307 * owner of this rwlock, clear the ownership
308 * information even if there are still more
309 * readers.
310 *
311 * This is the limitation of the detection
312 * mechanism rooted in the fact that tracking
313 * all readers would require dynamically
314 * allocated memory for keeping linkage info.
315 */
316 frw->oi.owned_by = NULL;
317 }
318
319 return;
320 }
321 } else {
322 frw->writers--;
323 }
324
325 assert(!frw->readers && !frw->writers);
326
327 frw->oi.owned_by = NULL;
328
329 while (!list_empty(&frw->waiters)) {
330 link_t *tmp = list_first(&frw->waiters);
331 awaiter_t *wdp;
332 fibril_t *f;
333
334 wdp = list_get_instance(tmp, awaiter_t, link);
335 f = (fibril_t *) wdp->fid;
336
337 if (f->is_writer) {
338 if (frw->readers)
339 break;
340 frw->writers++;
341 } else {
342 frw->readers++;
343 }
344
345 f->waits_for = NULL;
346 list_remove(&wdp->link);
347 frw->oi.owned_by = f;
348 fibril_notify(&wdp->event);
349
350 if (frw->writers)
351 break;
352 }
353}
354
355void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
356{
357 futex_lock(&fibril_synch_futex);
358 assert(frw->readers > 0);
359 _fibril_rwlock_common_unlock(frw);
360 futex_unlock(&fibril_synch_futex);
361}
362
363void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
364{
365 futex_lock(&fibril_synch_futex);
366 assert(frw->writers == 1);
367 assert(frw->oi.owned_by == fibril_self());
368 _fibril_rwlock_common_unlock(frw);
369 futex_unlock(&fibril_synch_futex);
370}
371
372bool fibril_rwlock_is_read_locked(fibril_rwlock_t *frw)
373{
374 futex_lock(&fibril_synch_futex);
375 bool locked = (frw->readers > 0);
376 futex_unlock(&fibril_synch_futex);
377 return locked;
378}
379
380bool fibril_rwlock_is_write_locked(fibril_rwlock_t *frw)
381{
382 futex_lock(&fibril_synch_futex);
383 assert(frw->writers <= 1);
384 bool locked = (frw->writers > 0) && (frw->oi.owned_by == fibril_self());
385 futex_unlock(&fibril_synch_futex);
386 return locked;
387}
388
389bool fibril_rwlock_is_locked(fibril_rwlock_t *frw)
390{
391 return fibril_rwlock_is_read_locked(frw) ||
392 fibril_rwlock_is_write_locked(frw);
393}
394
395void fibril_condvar_initialize(fibril_condvar_t *fcv)
396{
397 list_initialize(&fcv->waiters);
398}
399
400/**
401 * FIXME: If `timeout` is negative, the function returns ETIMEOUT immediately,
402 * and if `timeout` is 0, the wait never times out.
403 * This is not consistent with other similar APIs.
404 */
405errno_t
406fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
407 usec_t timeout)
408{
409 assert(fibril_mutex_is_locked(fm));
410
411 if (timeout < 0)
412 return ETIMEOUT;
413
414 awaiter_t wdata = AWAITER_INIT;
415 wdata.mutex = fm;
416
417 struct timespec ts;
418 struct timespec *expires = NULL;
419 if (timeout) {
420 getuptime(&ts);
421 ts_add_diff(&ts, USEC2NSEC(timeout));
422 expires = &ts;
423 }
424
425 futex_lock(&fibril_synch_futex);
426 _fibril_mutex_unlock_unsafe(fm);
427 list_append(&wdata.link, &fcv->waiters);
428 futex_unlock(&fibril_synch_futex);
429
430 (void) fibril_wait_timeout(&wdata.event, expires);
431
432 futex_lock(&fibril_synch_futex);
433 bool timed_out = link_in_use(&wdata.link);
434 list_remove(&wdata.link);
435 futex_unlock(&fibril_synch_futex);
436
437 fibril_mutex_lock(fm);
438
439 return timed_out ? ETIMEOUT : EOK;
440}
441
442void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
443{
444 (void) fibril_condvar_wait_timeout(fcv, fm, 0);
445}
446
447void fibril_condvar_signal(fibril_condvar_t *fcv)
448{
449 futex_lock(&fibril_synch_futex);
450
451 awaiter_t *w = list_pop(&fcv->waiters, awaiter_t, link);
452 if (w != NULL)
453 fibril_notify(&w->event);
454
455 futex_unlock(&fibril_synch_futex);
456}
457
458void fibril_condvar_broadcast(fibril_condvar_t *fcv)
459{
460 futex_lock(&fibril_synch_futex);
461
462 awaiter_t *w;
463 while ((w = list_pop(&fcv->waiters, awaiter_t, link)))
464 fibril_notify(&w->event);
465
466 futex_unlock(&fibril_synch_futex);
467}
468
469/** Timer fibril.
470 *
471 * @param arg Timer
472 */
473static errno_t fibril_timer_func(void *arg)
474{
475 fibril_timer_t *timer = (fibril_timer_t *) arg;
476 errno_t rc;
477
478 fibril_mutex_lock(timer->lockp);
479
480 while (timer->state != fts_cleanup) {
481 switch (timer->state) {
482 case fts_not_set:
483 case fts_fired:
484 fibril_condvar_wait(&timer->cv, timer->lockp);
485 break;
486 case fts_active:
487 rc = fibril_condvar_wait_timeout(&timer->cv,
488 timer->lockp, timer->delay);
489 if (rc == ETIMEOUT && timer->state == fts_active) {
490 timer->state = fts_fired;
491 timer->handler_fid = fibril_get_id();
492 fibril_mutex_unlock(timer->lockp);
493 timer->fun(timer->arg);
494 fibril_mutex_lock(timer->lockp);
495 timer->handler_fid = 0;
496 }
497 break;
498 case fts_cleanup:
499 case fts_clean:
500 assert(false);
501 break;
502 }
503 }
504
505 /* Acknowledge timer fibril has finished cleanup. */
506 timer->state = fts_clean;
507 fibril_condvar_broadcast(&timer->cv);
508 fibril_mutex_unlock(timer->lockp);
509
510 return 0;
511}
512
513/** Create new timer.
514 *
515 * @return New timer on success, @c NULL if out of memory.
516 */
517fibril_timer_t *fibril_timer_create(fibril_mutex_t *lock)
518{
519 fid_t fid;
520 fibril_timer_t *timer;
521
522 timer = calloc(1, sizeof(fibril_timer_t));
523 if (timer == NULL)
524 return NULL;
525
526 fid = fibril_create(fibril_timer_func, (void *) timer);
527 if (fid == 0) {
528 free(timer);
529 return NULL;
530 }
531
532 fibril_mutex_initialize(&timer->lock);
533 fibril_condvar_initialize(&timer->cv);
534
535 timer->fibril = fid;
536 timer->state = fts_not_set;
537 timer->lockp = (lock != NULL) ? lock : &timer->lock;
538
539 fibril_add_ready(fid);
540 return timer;
541}
542
543/** Destroy timer.
544 *
545 * @param timer Timer, must not be active or accessed by other threads.
546 */
547void fibril_timer_destroy(fibril_timer_t *timer)
548{
549 fibril_mutex_lock(timer->lockp);
550 assert(timer->state == fts_not_set || timer->state == fts_fired);
551
552 /* Request timer fibril to terminate. */
553 timer->state = fts_cleanup;
554 fibril_condvar_broadcast(&timer->cv);
555
556 /* Wait for timer fibril to terminate */
557 while (timer->state != fts_clean)
558 fibril_condvar_wait(&timer->cv, timer->lockp);
559 fibril_mutex_unlock(timer->lockp);
560
561 free(timer);
562}
563
564/** Set timer.
565 *
566 * Set timer to execute a callback function after the specified
567 * interval.
568 *
569 * @param timer Timer
570 * @param delay Delay in microseconds
571 * @param fun Callback function
572 * @param arg Argument for @a fun
573 */
574void fibril_timer_set(fibril_timer_t *timer, usec_t delay,
575 fibril_timer_fun_t fun, void *arg)
576{
577 fibril_mutex_lock(timer->lockp);
578 fibril_timer_set_locked(timer, delay, fun, arg);
579 fibril_mutex_unlock(timer->lockp);
580}
581
582/** Set locked timer.
583 *
584 * Set timer to execute a callback function after the specified
585 * interval. Must be called when the timer is locked.
586 *
587 * @param timer Timer
588 * @param delay Delay in microseconds
589 * @param fun Callback function
590 * @param arg Argument for @a fun
591 */
592void fibril_timer_set_locked(fibril_timer_t *timer, usec_t delay,
593 fibril_timer_fun_t fun, void *arg)
594{
595 assert(fibril_mutex_is_locked(timer->lockp));
596 assert(timer->state == fts_not_set || timer->state == fts_fired);
597 timer->state = fts_active;
598 timer->delay = delay;
599 timer->fun = fun;
600 timer->arg = arg;
601 fibril_condvar_broadcast(&timer->cv);
602}
603
604/** Clear timer.
605 *
606 * Clears (cancels) timer and returns last state of the timer.
607 * This can be one of:
608 * - fts_not_set If the timer has not been set or has been cleared
609 * - fts_active Timer was set but did not fire
610 * - fts_fired Timer fired
611 *
612 * @param timer Timer
613 * @return Last timer state
614 */
615fibril_timer_state_t fibril_timer_clear(fibril_timer_t *timer)
616{
617 fibril_timer_state_t old_state;
618
619 fibril_mutex_lock(timer->lockp);
620 old_state = fibril_timer_clear_locked(timer);
621 fibril_mutex_unlock(timer->lockp);
622
623 return old_state;
624}
625
626/** Clear locked timer.
627 *
628 * Clears (cancels) timer and returns last state of the timer.
629 * This can be one of:
630 * - fts_not_set If the timer has not been set or has been cleared
631 * - fts_active Timer was set but did not fire
632 * - fts_fired Timer fired
633 * Must be called when the timer is locked.
634 *
635 * @param timer Timer
636 * @return Last timer state
637 */
638fibril_timer_state_t fibril_timer_clear_locked(fibril_timer_t *timer)
639{
640 fibril_timer_state_t old_state;
641
642 assert(fibril_mutex_is_locked(timer->lockp));
643
644 while (timer->handler_fid != 0) {
645 if (timer->handler_fid == fibril_get_id()) {
646 printf("Deadlock detected.\n");
647 stacktrace_print();
648 printf("Fibril %p is trying to clear timer %p from "
649 "inside its handler %p.\n",
650 fibril_get_id(), timer, timer->fun);
651 abort();
652 }
653
654 fibril_condvar_wait(&timer->cv, timer->lockp);
655 }
656
657 old_state = timer->state;
658 timer->state = fts_not_set;
659
660 timer->delay = 0;
661 timer->fun = NULL;
662 timer->arg = NULL;
663 fibril_condvar_broadcast(&timer->cv);
664
665 return old_state;
666}
667
668/**
669 * Initialize a semaphore with initial count set to the provided value.
670 *
671 * @param sem Semaphore to initialize.
672 * @param count Initial count. Must not be negative.
673 */
674void fibril_semaphore_initialize(fibril_semaphore_t *sem, long count)
675{
676 /*
677 * Negative count denotes the length of waitlist,
678 * so it makes no sense as an initial value.
679 */
680 assert(count >= 0);
681 sem->closed = false;
682 sem->count = count;
683 list_initialize(&sem->waiters);
684}
685
686/**
687 * Produce one token.
688 * If there are fibrils waiting for tokens, this operation satisfies
689 * exactly one waiting `fibril_semaphore_down()`.
690 * This operation never blocks the fibril.
691 *
692 * @param sem Semaphore to use.
693 */
694void fibril_semaphore_up(fibril_semaphore_t *sem)
695{
696 futex_lock(&fibril_synch_futex);
697
698 if (sem->closed) {
699 futex_unlock(&fibril_synch_futex);
700 return;
701 }
702
703 sem->count++;
704
705 if (sem->count <= 0) {
706 awaiter_t *w = list_pop(&sem->waiters, awaiter_t, link);
707 assert(w);
708 fibril_notify(&w->event);
709 }
710
711 futex_unlock(&fibril_synch_futex);
712}
713
714/**
715 * Consume one token.
716 * If there are no available tokens (count <= 0), this operation blocks until
717 * another fibril produces a token using `fibril_semaphore_up()`.
718 *
719 * @param sem Semaphore to use.
720 */
721void fibril_semaphore_down(fibril_semaphore_t *sem)
722{
723 futex_lock(&fibril_synch_futex);
724
725 if (sem->closed) {
726 futex_unlock(&fibril_synch_futex);
727 return;
728 }
729
730 sem->count--;
731
732 if (sem->count >= 0) {
733 futex_unlock(&fibril_synch_futex);
734 return;
735 }
736
737 awaiter_t wdata = AWAITER_INIT;
738 list_append(&wdata.link, &sem->waiters);
739
740 futex_unlock(&fibril_synch_futex);
741
742 fibril_wait_for(&wdata.event);
743}
744
745errno_t fibril_semaphore_down_timeout(fibril_semaphore_t *sem, usec_t timeout)
746{
747 if (timeout < 0)
748 return ETIMEOUT;
749
750 futex_lock(&fibril_synch_futex);
751 if (sem->closed) {
752 futex_unlock(&fibril_synch_futex);
753 return EOK;
754 }
755
756 sem->count--;
757
758 if (sem->count >= 0) {
759 futex_unlock(&fibril_synch_futex);
760 return EOK;
761 }
762
763 awaiter_t wdata = AWAITER_INIT;
764 list_append(&wdata.link, &sem->waiters);
765
766 futex_unlock(&fibril_synch_futex);
767
768 struct timespec ts;
769 struct timespec *expires = NULL;
770 if (timeout) {
771 getuptime(&ts);
772 ts_add_diff(&ts, USEC2NSEC(timeout));
773 expires = &ts;
774 }
775
776 errno_t rc = fibril_wait_timeout(&wdata.event, expires);
777 if (rc == EOK)
778 return EOK;
779
780 futex_lock(&fibril_synch_futex);
781 if (!link_in_use(&wdata.link)) {
782 futex_unlock(&fibril_synch_futex);
783 return EOK;
784 }
785
786 list_remove(&wdata.link);
787 sem->count++;
788 futex_unlock(&fibril_synch_futex);
789
790 return rc;
791}
792
793/**
794 * Close the semaphore.
795 * All future down() operations return instantly.
796 */
797void fibril_semaphore_close(fibril_semaphore_t *sem)
798{
799 futex_lock(&fibril_synch_futex);
800 sem->closed = true;
801 awaiter_t *w;
802
803 while ((w = list_pop(&sem->waiters, awaiter_t, link)))
804 fibril_notify(&w->event);
805
806 futex_unlock(&fibril_synch_futex);
807}
808
809/** @}
810 */
Note: See TracBrowser for help on using the repository browser.