feat: simple read/write lock implementation
[lunaix-os.git] / 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 (file)
index 0000000..383e4c4
--- /dev/null
@@ -0,0 +1,58 @@
+#include <lunaix/ds/rwlock.h>
+#include <lunaix/spike.h>
+
+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