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

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

Make fibril RW-locks use the awaiter_t type for sleeping.
Timeouts are not supported.

  • Property mode set to 100644
File size: 7.3 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_sync.h>
36#include <fibril.h>
37#include <async.h>
38#include <async_priv.h>
39#include <adt/list.h>
40#include <futex.h>
41#include <sys/time.h>
42#include <errno.h>
43#include <assert.h>
44
45static void optimize_execution_power(void)
46{
47 /*
48 * When waking up a worker fibril previously blocked in fibril
49 * synchronization, chances are that there is an idle manager fibril
50 * waiting for IPC, that could start executing the awakened worker
51 * fibril right away. We try to detect this and bring the manager
52 * fibril back to fruitful work.
53 */
54 if (atomic_get(&threads_in_ipc_wait) > 0)
55 ipc_poke();
56}
57
58void fibril_mutex_initialize(fibril_mutex_t *fm)
59{
60 fm->counter = 1;
61 list_initialize(&fm->waiters);
62}
63
64void fibril_mutex_lock(fibril_mutex_t *fm)
65{
66 futex_down(&async_futex);
67 if (fm->counter-- <= 0) {
68 awaiter_t wdata;
69
70 wdata.fid = fibril_get_id();
71 wdata.active = false;
72 wdata.wu_event.inlist = true;
73 link_initialize(&wdata.wu_event.link);
74 list_append(&wdata.wu_event.link, &fm->waiters);
75 fibril_switch(FIBRIL_TO_MANAGER);
76 } else {
77 futex_up(&async_futex);
78 }
79}
80
81bool fibril_mutex_trylock(fibril_mutex_t *fm)
82{
83 bool locked = false;
84
85 futex_down(&async_futex);
86 if (fm->counter > 0) {
87 fm->counter--;
88 locked = true;
89 }
90 futex_up(&async_futex);
91
92 return locked;
93}
94
95static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
96{
97 assert(fm->counter <= 0);
98 if (fm->counter++ < 0) {
99 link_t *tmp;
100 awaiter_t *wdp;
101
102 assert(!list_empty(&fm->waiters));
103 tmp = fm->waiters.next;
104 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
105 wdp->wu_event.inlist = false;
106 list_remove(&wdp->wu_event.link);
107 fibril_add_ready(wdp->fid);
108 optimize_execution_power();
109 }
110}
111
112void fibril_mutex_unlock(fibril_mutex_t *fm)
113{
114 futex_down(&async_futex);
115 _fibril_mutex_unlock_unsafe(fm);
116 futex_up(&async_futex);
117}
118
119void fibril_rwlock_initialize(fibril_rwlock_t *frw)
120{
121 frw->writers = 0;
122 frw->readers = 0;
123 list_initialize(&frw->waiters);
124}
125
126void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
127{
128 futex_down(&async_futex);
129 if (frw->writers) {
130 fibril_t *f = (fibril_t *) fibril_get_id();
131 awaiter_t wdata;
132
133 wdata.fid = (fid_t) f;
134 wdata.active = false;
135 wdata.wu_event.inlist = true;
136 link_initialize(&wdata.wu_event.link);
137 f->flags &= ~FIBRIL_WRITER;
138 list_append(&wdata.wu_event.link, &frw->waiters);
139 fibril_switch(FIBRIL_TO_MANAGER);
140 } else {
141 frw->readers++;
142 futex_up(&async_futex);
143 }
144}
145
146void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
147{
148 futex_down(&async_futex);
149 if (frw->writers || frw->readers) {
150 fibril_t *f = (fibril_t *) fibril_get_id();
151 awaiter_t wdata;
152
153 wdata.fid = (fid_t) f;
154 wdata.active = false;
155 wdata.wu_event.inlist = true;
156 link_initialize(&wdata.wu_event.link);
157 f->flags |= FIBRIL_WRITER;
158 list_append(&wdata.wu_event.link, &frw->waiters);
159 fibril_switch(FIBRIL_TO_MANAGER);
160 } else {
161 frw->writers++;
162 futex_up(&async_futex);
163 }
164}
165
166static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
167{
168 futex_down(&async_futex);
169 assert(frw->readers || (frw->writers == 1));
170 if (frw->readers) {
171 if (--frw->readers)
172 goto out;
173 } else {
174 frw->writers--;
175 }
176
177 assert(!frw->readers && !frw->writers);
178
179 while (!list_empty(&frw->waiters)) {
180 link_t *tmp = frw->waiters.next;
181 awaiter_t *wdp;
182 fibril_t *f;
183
184 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
185 f = (fibril_t *) wdp->fid;
186
187 if (f->flags & FIBRIL_WRITER) {
188 if (frw->readers)
189 break;
190 wdp->active = true;
191 wdp->wu_event.inlist = false;
192 list_remove(&wdp->wu_event.link);
193 fibril_add_ready(wdp->fid);
194 frw->writers++;
195 optimize_execution_power();
196 break;
197 } else {
198 wdp->active = true;
199 wdp->wu_event.inlist = false;
200 list_remove(&wdp->wu_event.link);
201 fibril_add_ready(wdp->fid);
202 frw->readers++;
203 optimize_execution_power();
204 }
205 }
206out:
207 futex_up(&async_futex);
208}
209
210void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
211{
212 _fibril_rwlock_common_unlock(frw);
213}
214
215void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
216{
217 _fibril_rwlock_common_unlock(frw);
218}
219
220void fibril_condvar_initialize(fibril_condvar_t *fcv)
221{
222 list_initialize(&fcv->waiters);
223}
224
225int
226fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
227 suseconds_t timeout)
228{
229 awaiter_t wdata;
230
231 if (timeout < 0)
232 return ETIMEOUT;
233
234 wdata.fid = fibril_get_id();
235 wdata.active = false;
236
237 wdata.to_event.inlist = timeout > 0;
238 wdata.to_event.occurred = false;
239 link_initialize(&wdata.to_event.link);
240
241 wdata.wu_event.inlist = true;
242 link_initialize(&wdata.wu_event.link);
243
244 futex_down(&async_futex);
245 if (timeout) {
246 gettimeofday(&wdata.to_event.expires, NULL);
247 tv_add(&wdata.to_event.expires, timeout);
248 async_insert_timeout(&wdata);
249 }
250 list_append(&wdata.wu_event.link, &fcv->waiters);
251 _fibril_mutex_unlock_unsafe(fm);
252 fibril_switch(FIBRIL_TO_MANAGER);
253 fibril_mutex_lock(fm);
254
255 /* async_futex not held after fibril_switch() */
256 futex_down(&async_futex);
257 if (wdata.to_event.inlist)
258 list_remove(&wdata.to_event.link);
259 if (wdata.wu_event.inlist)
260 list_remove(&wdata.wu_event.link);
261 futex_up(&async_futex);
262
263 return wdata.to_event.occurred ? ETIMEOUT : EOK;
264}
265
266void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
267{
268 int rc;
269
270 rc = fibril_condvar_wait_timeout(fcv, fm, 0);
271 assert(rc == EOK);
272}
273
274static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once)
275{
276 link_t *tmp;
277 awaiter_t *wdp;
278
279 futex_down(&async_futex);
280 while (!list_empty(&fcv->waiters)) {
281 tmp = fcv->waiters.next;
282 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
283 list_remove(&wdp->wu_event.link);
284 wdp->wu_event.inlist = false;
285 if (!wdp->active) {
286 wdp->active = true;
287 fibril_add_ready(wdp->fid);
288 optimize_execution_power();
289 if (once)
290 break;
291 }
292 }
293 futex_up(&async_futex);
294}
295
296void fibril_condvar_signal(fibril_condvar_t *fcv)
297{
298 _fibril_condvar_wakeup_common(fcv, true);
299}
300
301void fibril_condvar_broadcast(fibril_condvar_t *fcv)
302{
303 _fibril_condvar_wakeup_common(fcv, false);
304}
305
306/** @}
307 */
Note: See TracBrowser for help on using the repository browser.