00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <fibril_synch.h>
00036 #include <fibril.h>
00037 #include <async.h>
00038 #include <adt/list.h>
00039 #include <futex.h>
00040 #include <sys/time.h>
00041 #include <errno.h>
00042 #include <assert.h>
00043 #include <stacktrace.h>
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 #include "private/async.h"
00047
00048 static void optimize_execution_power(void)
00049 {
00050
00051
00052
00053
00054
00055
00056
00057 if (atomic_get(&threads_in_ipc_wait) > 0)
00058 async_poke();
00059 }
00060
00061 static void print_deadlock(fibril_owner_info_t *oi)
00062 {
00063 fibril_t *f = (fibril_t *) fibril_get_id();
00064
00065 printf("Deadlock detected.\n");
00066 stacktrace_print();
00067
00068 printf("Fibril %p waits for primitive %p.\n", f, oi);
00069
00070 while (oi && oi->owned_by) {
00071 printf("Primitive %p is owned by fibril %p.\n",
00072 oi, oi->owned_by);
00073 if (oi->owned_by == f)
00074 break;
00075 stacktrace_print_fp_pc(context_get_fp(&oi->owned_by->ctx),
00076 oi->owned_by->ctx.pc);
00077 printf("Fibril %p waits for primitive %p.\n",
00078 oi->owned_by, oi->owned_by->waits_for);
00079 oi = oi->owned_by->waits_for;
00080 }
00081 }
00082
00083
00084 static void check_for_deadlock(fibril_owner_info_t *oi)
00085 {
00086 while (oi && oi->owned_by) {
00087 if (oi->owned_by == (fibril_t *) fibril_get_id()) {
00088 print_deadlock(oi);
00089 abort();
00090 }
00091 oi = oi->owned_by->waits_for;
00092 }
00093 }
00094
00095
00096 void fibril_mutex_initialize(fibril_mutex_t *fm)
00097 {
00098 fm->oi.owned_by = NULL;
00099 fm->counter = 1;
00100 list_initialize(&fm->waiters);
00101 }
00102
00103 void fibril_mutex_lock(fibril_mutex_t *fm)
00104 {
00105 fibril_t *f = (fibril_t *) fibril_get_id();
00106
00107 if (fibril_get_sercount() != 0)
00108 abort();
00109
00110 futex_down(&async_futex);
00111 if (fm->counter-- <= 0) {
00112 awaiter_t wdata;
00113
00114 wdata.fid = fibril_get_id();
00115 wdata.active = false;
00116 wdata.wu_event.inlist = true;
00117 link_initialize(&wdata.wu_event.link);
00118 list_append(&wdata.wu_event.link, &fm->waiters);
00119 check_for_deadlock(&fm->oi);
00120 f->waits_for = &fm->oi;
00121 fibril_switch(FIBRIL_TO_MANAGER);
00122 } else {
00123 fm->oi.owned_by = f;
00124 futex_up(&async_futex);
00125 }
00126 }
00127
00128 bool fibril_mutex_trylock(fibril_mutex_t *fm)
00129 {
00130 bool locked = false;
00131
00132 futex_down(&async_futex);
00133 if (fm->counter > 0) {
00134 fm->counter--;
00135 fm->oi.owned_by = (fibril_t *) fibril_get_id();
00136 locked = true;
00137 }
00138 futex_up(&async_futex);
00139
00140 return locked;
00141 }
00142
00143 static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
00144 {
00145 if (fm->counter++ < 0) {
00146 link_t *tmp;
00147 awaiter_t *wdp;
00148 fibril_t *f;
00149
00150 assert(!list_empty(&fm->waiters));
00151 tmp = fm->waiters.next;
00152 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
00153 wdp->active = true;
00154 wdp->wu_event.inlist = false;
00155
00156 f = (fibril_t *) wdp->fid;
00157 fm->oi.owned_by = f;
00158 f->waits_for = NULL;
00159
00160 list_remove(&wdp->wu_event.link);
00161 fibril_add_ready(wdp->fid);
00162 optimize_execution_power();
00163 } else {
00164 fm->oi.owned_by = NULL;
00165 }
00166 }
00167
00168 void fibril_mutex_unlock(fibril_mutex_t *fm)
00169 {
00170 assert(fibril_mutex_is_locked(fm));
00171 futex_down(&async_futex);
00172 _fibril_mutex_unlock_unsafe(fm);
00173 futex_up(&async_futex);
00174 }
00175
00176 bool fibril_mutex_is_locked(fibril_mutex_t *fm)
00177 {
00178 bool locked = false;
00179
00180 futex_down(&async_futex);
00181 if (fm->counter <= 0)
00182 locked = true;
00183 futex_up(&async_futex);
00184
00185 return locked;
00186 }
00187
00188 void fibril_rwlock_initialize(fibril_rwlock_t *frw)
00189 {
00190 frw->oi.owned_by = NULL;
00191 frw->writers = 0;
00192 frw->readers = 0;
00193 list_initialize(&frw->waiters);
00194 }
00195
00196 void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
00197 {
00198 fibril_t *f = (fibril_t *) fibril_get_id();
00199
00200 if (fibril_get_sercount() != 0)
00201 abort();
00202
00203 futex_down(&async_futex);
00204 if (frw->writers) {
00205 awaiter_t wdata;
00206
00207 wdata.fid = (fid_t) f;
00208 wdata.active = false;
00209 wdata.wu_event.inlist = true;
00210 link_initialize(&wdata.wu_event.link);
00211 f->flags &= ~FIBRIL_WRITER;
00212 list_append(&wdata.wu_event.link, &frw->waiters);
00213 check_for_deadlock(&frw->oi);
00214 f->waits_for = &frw->oi;
00215 fibril_switch(FIBRIL_TO_MANAGER);
00216 } else {
00217
00218 if (frw->readers++ == 0)
00219 frw->oi.owned_by = f;
00220 futex_up(&async_futex);
00221 }
00222 }
00223
00224 void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
00225 {
00226 fibril_t *f = (fibril_t *) fibril_get_id();
00227
00228 if (fibril_get_sercount() != 0)
00229 abort();
00230
00231 futex_down(&async_futex);
00232 if (frw->writers || frw->readers) {
00233 awaiter_t wdata;
00234
00235 wdata.fid = (fid_t) f;
00236 wdata.active = false;
00237 wdata.wu_event.inlist = true;
00238 link_initialize(&wdata.wu_event.link);
00239 f->flags |= FIBRIL_WRITER;
00240 list_append(&wdata.wu_event.link, &frw->waiters);
00241 check_for_deadlock(&frw->oi);
00242 f->waits_for = &frw->oi;
00243 fibril_switch(FIBRIL_TO_MANAGER);
00244 } else {
00245 frw->oi.owned_by = f;
00246 frw->writers++;
00247 futex_up(&async_futex);
00248 }
00249 }
00250
00251 static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
00252 {
00253 futex_down(&async_futex);
00254 if (frw->readers) {
00255 if (--frw->readers) {
00256 if (frw->oi.owned_by == (fibril_t *) fibril_get_id()) {
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 frw->oi.owned_by = NULL;
00269 }
00270 goto out;
00271 }
00272 } else {
00273 frw->writers--;
00274 }
00275
00276 assert(!frw->readers && !frw->writers);
00277
00278 frw->oi.owned_by = NULL;
00279
00280 while (!list_empty(&frw->waiters)) {
00281 link_t *tmp = frw->waiters.next;
00282 awaiter_t *wdp;
00283 fibril_t *f;
00284
00285 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
00286 f = (fibril_t *) wdp->fid;
00287
00288 f->waits_for = NULL;
00289
00290 if (f->flags & FIBRIL_WRITER) {
00291 if (frw->readers)
00292 break;
00293 wdp->active = true;
00294 wdp->wu_event.inlist = false;
00295 list_remove(&wdp->wu_event.link);
00296 fibril_add_ready(wdp->fid);
00297 frw->writers++;
00298 frw->oi.owned_by = f;
00299 optimize_execution_power();
00300 break;
00301 } else {
00302 wdp->active = true;
00303 wdp->wu_event.inlist = false;
00304 list_remove(&wdp->wu_event.link);
00305 fibril_add_ready(wdp->fid);
00306 if (frw->readers++ == 0) {
00307
00308 frw->oi.owned_by = f;
00309 }
00310 optimize_execution_power();
00311 }
00312 }
00313 out:
00314 futex_up(&async_futex);
00315 }
00316
00317 void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
00318 {
00319 assert(fibril_rwlock_is_read_locked(frw));
00320 _fibril_rwlock_common_unlock(frw);
00321 }
00322
00323 void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
00324 {
00325 assert(fibril_rwlock_is_write_locked(frw));
00326 _fibril_rwlock_common_unlock(frw);
00327 }
00328
00329 bool fibril_rwlock_is_read_locked(fibril_rwlock_t *frw)
00330 {
00331 bool locked = false;
00332
00333 futex_down(&async_futex);
00334 if (frw->readers)
00335 locked = true;
00336 futex_up(&async_futex);
00337
00338 return locked;
00339 }
00340
00341 bool fibril_rwlock_is_write_locked(fibril_rwlock_t *frw)
00342 {
00343 bool locked = false;
00344
00345 futex_down(&async_futex);
00346 if (frw->writers) {
00347 assert(frw->writers == 1);
00348 locked = true;
00349 }
00350 futex_up(&async_futex);
00351
00352 return locked;
00353 }
00354
00355 bool fibril_rwlock_is_locked(fibril_rwlock_t *frw)
00356 {
00357 return fibril_rwlock_is_read_locked(frw) ||
00358 fibril_rwlock_is_write_locked(frw);
00359 }
00360
00361 void fibril_condvar_initialize(fibril_condvar_t *fcv)
00362 {
00363 list_initialize(&fcv->waiters);
00364 }
00365
00366 int
00367 fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
00368 suseconds_t timeout)
00369 {
00370 awaiter_t wdata;
00371
00372 assert(fibril_mutex_is_locked(fm));
00373
00374 if (timeout < 0)
00375 return ETIMEOUT;
00376
00377 wdata.fid = fibril_get_id();
00378 wdata.active = false;
00379
00380 wdata.to_event.inlist = timeout > 0;
00381 wdata.to_event.occurred = false;
00382 link_initialize(&wdata.to_event.link);
00383
00384 wdata.wu_event.inlist = true;
00385 link_initialize(&wdata.wu_event.link);
00386
00387 futex_down(&async_futex);
00388 if (timeout) {
00389 gettimeofday(&wdata.to_event.expires, NULL);
00390 tv_add(&wdata.to_event.expires, timeout);
00391 async_insert_timeout(&wdata);
00392 }
00393 list_append(&wdata.wu_event.link, &fcv->waiters);
00394 _fibril_mutex_unlock_unsafe(fm);
00395 fibril_switch(FIBRIL_TO_MANAGER);
00396 fibril_mutex_lock(fm);
00397
00398
00399 futex_down(&async_futex);
00400 if (wdata.to_event.inlist)
00401 list_remove(&wdata.to_event.link);
00402 if (wdata.wu_event.inlist)
00403 list_remove(&wdata.wu_event.link);
00404 futex_up(&async_futex);
00405
00406 return wdata.to_event.occurred ? ETIMEOUT : EOK;
00407 }
00408
00409 void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
00410 {
00411 int rc;
00412
00413 rc = fibril_condvar_wait_timeout(fcv, fm, 0);
00414 assert(rc == EOK);
00415 }
00416
00417 static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once)
00418 {
00419 link_t *tmp;
00420 awaiter_t *wdp;
00421
00422 futex_down(&async_futex);
00423 while (!list_empty(&fcv->waiters)) {
00424 tmp = fcv->waiters.next;
00425 wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
00426 list_remove(&wdp->wu_event.link);
00427 wdp->wu_event.inlist = false;
00428 if (!wdp->active) {
00429 wdp->active = true;
00430 fibril_add_ready(wdp->fid);
00431 optimize_execution_power();
00432 if (once)
00433 break;
00434 }
00435 }
00436 futex_up(&async_futex);
00437 }
00438
00439 void fibril_condvar_signal(fibril_condvar_t *fcv)
00440 {
00441 _fibril_condvar_wakeup_common(fcv, true);
00442 }
00443
00444 void fibril_condvar_broadcast(fibril_condvar_t *fcv)
00445 {
00446 _fibril_condvar_wakeup_common(fcv, false);
00447 }
00448