source: mainline/uspace/lib/libc/generic/fibril_sync.c@ b6ee5b1

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

Fibril synchronization needs to have a means to interrupt
idle threads from waiting for IPC and get them to execute
awakened fibrils.

  • Property mode set to 100644
File size: 5.6 KB
RevLine 
[f3afd24]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_sync.h>
36#include <fibril.h>
37#include <async.h>
38#include <adt/list.h>
39#include <futex.h>
40#include <assert.h>
41
[8619f25]42static void optimize_execution_power(void)
43{
44 /*
45 * When waking up a worker fibril previously blocked in fibril
46 * synchronization, chances are that there is an idle manager fibril
47 * waiting for IPC, that could start executing the awakened worker
48 * fibril right away. We try to detect this and bring the manager
49 * fibril back to fruitful work.
50 */
51 if (atomic_get(&threads_in_ipc_wait) > 0)
52 ipc_poke();
53}
54
[f3afd24]55void fibril_mutex_initialize(fibril_mutex_t *fm)
56{
57 fm->counter = 1;
58 list_initialize(&fm->waiters);
59}
60
61void fibril_mutex_lock(fibril_mutex_t *fm)
62{
63 futex_down(&async_futex);
64 if (fm->counter-- <= 0) {
65 fibril_t *f = (fibril_t *) fibril_get_id();
66 list_append(&f->link, &fm->waiters);
67 fibril_switch(FIBRIL_TO_MANAGER);
68 } else {
69 futex_up(&async_futex);
70 }
71}
72
73bool fibril_mutex_trylock(fibril_mutex_t *fm)
74{
75 bool locked = false;
76
77 futex_down(&async_futex);
78 if (fm->counter > 0) {
79 fm->counter--;
80 locked = true;
81 }
82 futex_up(&async_futex);
83
84 return locked;
85}
86
[9ae22ba]87static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
[f3afd24]88{
89 assert(fm->counter <= 0);
90 if (fm->counter++ < 0) {
91 link_t *tmp;
92 fibril_t *f;
93
94 assert(!list_empty(&fm->waiters));
95 tmp = fm->waiters.next;
96 f = list_get_instance(tmp, fibril_t, link);
97 list_remove(&f->link);
98 fibril_add_ready((fid_t) f);
[8619f25]99 optimize_execution_power();
[f3afd24]100 }
[9ae22ba]101}
102
103void fibril_mutex_unlock(fibril_mutex_t *fm)
104{
105 futex_down(&async_futex);
106 _fibril_mutex_unlock_unsafe(fm);
[f3afd24]107 futex_up(&async_futex);
108}
109
110void fibril_rwlock_initialize(fibril_rwlock_t *frw)
111{
[92d34f0b]112 frw->writers = 0;
113 frw->readers = 0;
114 list_initialize(&frw->waiters);
[f3afd24]115}
116
117void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
118{
[92d34f0b]119 futex_down(&async_futex);
120 if (frw->writers) {
121 fibril_t *f = (fibril_t *) fibril_get_id();
122 f->flags &= ~FIBRIL_WRITER;
123 list_append(&f->link, &frw->waiters);
124 fibril_switch(FIBRIL_TO_MANAGER);
125 } else {
126 frw->readers++;
127 futex_up(&async_futex);
128 }
[f3afd24]129}
130
131void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
132{
[92d34f0b]133 futex_down(&async_futex);
134 if (frw->writers || frw->readers) {
135 fibril_t *f = (fibril_t *) fibril_get_id();
136 f->flags |= FIBRIL_WRITER;
137 list_append(&f->link, &frw->waiters);
138 fibril_switch(FIBRIL_TO_MANAGER);
139 } else {
140 frw->writers++;
141 futex_up(&async_futex);
142 }
143}
144
145static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
146{
147 futex_down(&async_futex);
148 assert(frw->readers || (frw->writers == 1));
149 if (frw->readers) {
150 if (--frw->readers)
151 goto out;
152 } else {
153 frw->writers--;
154 }
155
156 assert(!frw->readers && !frw->writers);
157
158 while (!list_empty(&frw->waiters)) {
159 link_t *tmp = frw->waiters.next;
160 fibril_t *f = list_get_instance(tmp, fibril_t, link);
161
162 if (f->flags & FIBRIL_WRITER) {
163 if (frw->readers)
164 break;
165 list_remove(&f->link);
166 fibril_add_ready((fid_t) f);
167 frw->writers++;
[8619f25]168 optimize_execution_power();
[92d34f0b]169 break;
170 } else {
171 list_remove(&f->link);
172 fibril_add_ready((fid_t) f);
173 frw->readers++;
[8619f25]174 optimize_execution_power();
[92d34f0b]175 }
176 }
177out:
178 futex_up(&async_futex);
[f3afd24]179}
180
181void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
182{
[92d34f0b]183 _fibril_rwlock_common_unlock(frw);
[f3afd24]184}
185
186void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
187{
[92d34f0b]188 _fibril_rwlock_common_unlock(frw);
[f3afd24]189}
190
[9ae22ba]191void fibril_condvar_initialize(fibril_condvar_t *fcv)
192{
193 list_initialize(&fcv->waiters);
194}
195
196void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
197{
198 fibril_t *f = (fibril_t *) fibril_get_id();
199
200 futex_down(&async_futex);
201 list_append(&f->link, &fcv->waiters);
202 _fibril_mutex_unlock_unsafe(fm);
203 fibril_switch(FIBRIL_TO_MANAGER);
204 fibril_mutex_lock(fm);
205}
206
207static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once)
208{
209 link_t *tmp;
210 fibril_t *f;
211
212 futex_down(&async_futex);
213 while (!list_empty(&fcv->waiters)) {
214 tmp = fcv->waiters.next;
215 f = list_get_instance(tmp, fibril_t, link);
[c51a7cd]216 list_remove(&f->link);
[9ae22ba]217 fibril_add_ready((fid_t) f);
[8619f25]218 optimize_execution_power();
[9ae22ba]219 if (once)
220 break;
221 }
222 futex_up(&async_futex);
223}
224
225void fibril_condvar_signal(fibril_condvar_t *fcv)
226{
227 _fibril_condvar_wakeup_common(fcv, true);
228}
229
230void fibril_condvar_broadcast(fibril_condvar_t *fcv)
231{
232 _fibril_condvar_wakeup_common(fcv, false);
233}
234
[f3afd24]235/** @}
236 */
Note: See TracBrowser for help on using the repository browser.