source: mainline/uspace/lib/libc/generic/fibril_synch.c@ 21f32ee1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 21f32ee1 was 1e4cada, checked in by Martin Decky <martin@…>, 16 years ago

rename fibril_sync.[ch] to fibril_synch.[ch]

  • Property mode set to 100644
File size: 7.4 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 <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->active = true;
106 wdp->wu_event.inlist = false;
107 list_remove(&wdp->wu_event.link);
108 fibril_add_ready(wdp->fid);
109 optimize_execution_power();
110 }
111}
112
113void fibril_mutex_unlock(fibril_mutex_t *fm)
114{
115 futex_down(&async_futex);
116 _fibril_mutex_unlock_unsafe(fm);
117 futex_up(&async_futex);
118}
119
120void fibril_rwlock_initialize(fibril_rwlock_t *frw)
121{
122 frw->writers = 0;
123 frw->readers = 0;
124 list_initialize(&frw->waiters);
125}
126
127void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
128{
129 futex_down(&async_futex);
130 if (frw->writers) {
131 fibril_t *f = (fibril_t *) fibril_get_id();
132 awaiter_t wdata;
133
134 wdata.fid = (fid_t) f;
135 wdata.active = false;
136 wdata.wu_event.inlist = true;
137 link_initialize(&wdata.wu_event.link);
138 f->flags &= ~FIBRIL_WRITER;
139 list_append(&wdata.wu_event.link, &frw->waiters);
140 fibril_switch(FIBRIL_TO_MANAGER);
141 } else {
142 frw->readers++;
143 futex_up(&async_futex);
144 }
145}
146
147void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
148{
149 futex_down(&async_futex);
150 if (frw->writers || frw->readers) {
151 fibril_t *f = (fibril_t *) fibril_get_id();
152 awaiter_t wdata;
153
154 wdata.fid = (fid_t) f;
155 wdata.active = false;
156 wdata.wu_event.inlist = true;
157 link_initialize(&wdata.wu_event.link);
158 f->flags |= FIBRIL_WRITER;
159 list_append(&wdata.wu_event.link, &frw->waiters);
160 fibril_switch(FIBRIL_TO_MANAGER);
161 } else {
162 frw->writers++;
163 futex_up(&async_futex);
164 }
165}
166
167static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
168{
169 futex_down(&async_futex);
170 assert(frw->readers || (frw->writers == 1));
171 if (frw->readers) {
172 if (--frw->readers)
173 goto out;
174 } else {
175 frw->writers--;
176 }
177
178 assert(!frw->readers && !frw->writers);
179
180 while (!list_empty(&frw->waiters)) {
181 link_t *tmp = frw->waiters.next;
182 awaiter_t *wdp;
183 fibril_t *f;
184
185 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
186 f = (fibril_t *) wdp->fid;
187
188 if (f->flags & FIBRIL_WRITER) {
189 if (frw->readers)
190 break;
191 wdp->active = true;
192 wdp->wu_event.inlist = false;
193 list_remove(&wdp->wu_event.link);
194 fibril_add_ready(wdp->fid);
195 frw->writers++;
196 optimize_execution_power();
197 break;
198 } else {
199 wdp->active = true;
200 wdp->wu_event.inlist = false;
201 list_remove(&wdp->wu_event.link);
202 fibril_add_ready(wdp->fid);
203 frw->readers++;
204 optimize_execution_power();
205 }
206 }
207out:
208 futex_up(&async_futex);
209}
210
211void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
212{
213 _fibril_rwlock_common_unlock(frw);
214}
215
216void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
217{
218 _fibril_rwlock_common_unlock(frw);
219}
220
221void fibril_condvar_initialize(fibril_condvar_t *fcv)
222{
223 list_initialize(&fcv->waiters);
224}
225
226int
227fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
228 suseconds_t timeout)
229{
230 awaiter_t wdata;
231
232 if (timeout < 0)
233 return ETIMEOUT;
234
235 wdata.fid = fibril_get_id();
236 wdata.active = false;
237
238 wdata.to_event.inlist = timeout > 0;
239 wdata.to_event.occurred = false;
240 link_initialize(&wdata.to_event.link);
241
242 wdata.wu_event.inlist = true;
243 link_initialize(&wdata.wu_event.link);
244
245 futex_down(&async_futex);
246 if (timeout) {
247 gettimeofday(&wdata.to_event.expires, NULL);
248 tv_add(&wdata.to_event.expires, timeout);
249 async_insert_timeout(&wdata);
250 }
251 list_append(&wdata.wu_event.link, &fcv->waiters);
252 _fibril_mutex_unlock_unsafe(fm);
253 fibril_switch(FIBRIL_TO_MANAGER);
254 fibril_mutex_lock(fm);
255
256 /* async_futex not held after fibril_switch() */
257 futex_down(&async_futex);
258 if (wdata.to_event.inlist)
259 list_remove(&wdata.to_event.link);
260 if (wdata.wu_event.inlist)
261 list_remove(&wdata.wu_event.link);
262 futex_up(&async_futex);
263
264 return wdata.to_event.occurred ? ETIMEOUT : EOK;
265}
266
267void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
268{
269 int rc;
270
271 rc = fibril_condvar_wait_timeout(fcv, fm, 0);
272 assert(rc == EOK);
273}
274
275static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once)
276{
277 link_t *tmp;
278 awaiter_t *wdp;
279
280 futex_down(&async_futex);
281 while (!list_empty(&fcv->waiters)) {
282 tmp = fcv->waiters.next;
283 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
284 list_remove(&wdp->wu_event.link);
285 wdp->wu_event.inlist = false;
286 if (!wdp->active) {
287 wdp->active = true;
288 fibril_add_ready(wdp->fid);
289 optimize_execution_power();
290 if (once)
291 break;
292 }
293 }
294 futex_up(&async_futex);
295}
296
297void fibril_condvar_signal(fibril_condvar_t *fcv)
298{
299 _fibril_condvar_wakeup_common(fcv, true);
300}
301
302void fibril_condvar_broadcast(fibril_condvar_t *fcv)
303{
304 _fibril_condvar_wakeup_common(fcv, false);
305}
306
307/** @}
308 */
Note: See TracBrowser for help on using the repository browser.