Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4525 → Rev 4526

/trunk/uspace/lib/libc/generic/fibril_sync.c
90,27 → 90,81
 
void fibril_rwlock_initialize(fibril_rwlock_t *frw)
{
fibril_mutex_initialize(&frw->fm);
frw->writers = 0;
frw->readers = 0;
list_initialize(&frw->waiters);
}
 
void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
{
fibril_mutex_lock(&frw->fm);
futex_down(&async_futex);
if (frw->writers) {
fibril_t *f = (fibril_t *) fibril_get_id();
f->flags &= ~FIBRIL_WRITER;
list_append(&f->link, &frw->waiters);
fibril_switch(FIBRIL_TO_MANAGER);
} else {
frw->readers++;
futex_up(&async_futex);
}
}
 
void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
{
fibril_mutex_lock(&frw->fm);
futex_down(&async_futex);
if (frw->writers || frw->readers) {
fibril_t *f = (fibril_t *) fibril_get_id();
f->flags |= FIBRIL_WRITER;
list_append(&f->link, &frw->waiters);
fibril_switch(FIBRIL_TO_MANAGER);
} else {
frw->writers++;
futex_up(&async_futex);
}
}
 
static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
{
futex_down(&async_futex);
assert(frw->readers || (frw->writers == 1));
if (frw->readers) {
if (--frw->readers)
goto out;
} else {
frw->writers--;
}
assert(!frw->readers && !frw->writers);
while (!list_empty(&frw->waiters)) {
link_t *tmp = frw->waiters.next;
fibril_t *f = list_get_instance(tmp, fibril_t, link);
if (f->flags & FIBRIL_WRITER) {
if (frw->readers)
break;
list_remove(&f->link);
fibril_add_ready((fid_t) f);
frw->writers++;
break;
} else {
list_remove(&f->link);
fibril_add_ready((fid_t) f);
frw->readers++;
}
}
out:
futex_up(&async_futex);
}
 
void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
{
fibril_mutex_unlock(&frw->fm);
_fibril_rwlock_common_unlock(frw);
}
 
void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
{
fibril_mutex_unlock(&frw->fm);
_fibril_rwlock_common_unlock(frw);
}
 
/** @}