source: mainline/uspace/lib/c/generic/fibril_synch.c@ 12c38f5

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

Do not attempt to print the caller's stack twice in print_deadlock().
Print the matching "waits for" - "owned by" pair together.

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