X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/c50398ab4cb09658b3b3fff74804d2f26df785e7..4b6190b935dd75d8ddd514a05c7c7343e32c0cdc:/lunaix-os/kernel/ds/rwlock.c diff --git a/lunaix-os/kernel/ds/rwlock.c b/lunaix-os/kernel/ds/rwlock.c new file mode 100644 index 0000000..383e4c4 --- /dev/null +++ b/lunaix-os/kernel/ds/rwlock.c @@ -0,0 +1,58 @@ +#include +#include + +void +rwlock_init(rwlock_t* rwlock) +{ + waitq_init(&rwlock->waiting_readers); + waitq_init(&rwlock->waiting_writers); + atomic_init(&rwlock->readers, 0); + atomic_flag_clear(&rwlock->writer); +} + +void +rwlock_begin_read(rwlock_t* rwlock) +{ + while (atomic_flag_test_and_set(&rwlock->writer)) { + pwait(&rwlock->waiting_readers); + } + atomic_fetch_add(&rwlock->readers, 1); + atomic_flag_clear(&rwlock->writer); + pwake_all(&rwlock->waiting_readers); +} + +void +rwlock_end_read(rwlock_t* rwlock) +{ + assert(atomic_load(&rwlock->readers) > 0); + atomic_fetch_sub(&rwlock->readers, 1); + + if (!atomic_load(&rwlock->readers)) { + pwake_one(&rwlock->waiting_writers); + } +} + +void +rwlock_begin_write(rwlock_t* rwlock) +{ + // first, acquire writer lock, prevent any incoming readers + while (atomic_flag_test_and_set(&rwlock->writer)) { + pwait(&rwlock->waiting_writers); + } + + // then, wait for reader finish the read. + while (atomic_load(&rwlock->readers)) { + pwait(&rwlock->waiting_writers); + } +} + +void +rwlock_end_write(rwlock_t* rwlock) +{ + atomic_flag_clear(&rwlock->writer); + if (waitq_empty(&rwlock->waiting_writers)) { + pwake_all(&rwlock->waiting_readers); + } else { + pwake_one(&rwlock->waiting_writers); + } +} \ No newline at end of file