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

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

Preallocate waitq handle during initialization

Do not clutter futex_down_composable() with the preallocation of the
wait queue handle and do it single-threadedly in futex_initialize().

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