[haiku-commits] r33543 - in haiku/trunk: headers/private/shared src/system/libroot/os

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 12 Oct 2009 13:19:33 +0200 (CEST)

Author: mmlr
Date: 2009-10-12 13:19:33 +0200 (Mon, 12 Oct 2009)
New Revision: 33543
Changeset: http://dev.haiku-os.org/changeset/33543/haiku

Added:
   haiku/trunk/headers/private/shared/locks.h
   haiku/trunk/src/system/libroot/os/locks.cpp
Modified:
   haiku/trunk/src/system/libroot/os/Jamfile
Log:
Adding mutex and rw_lock with the same interface as the kernel versions to
libroot. The mutex is a simple benaphore, the rw_lock is pretty much the same
as the one from libkernelland_emu but uses a mutex per lock instead of emulating
a global thread lock. Also added MutexLocking and RWLock{Read|Write}Locking and
AutoLockers based on them. It's cased with __cplusplus so the locks are also
usable from C. Everything's currently exposed in shared/private/locks.h but I
think we should make these locking primitves public.


Added: haiku/trunk/headers/private/shared/locks.h
===================================================================
--- haiku/trunk/headers/private/shared/locks.h                          (rev 0)
+++ haiku/trunk/headers/private/shared/locks.h  2009-10-12 11:19:33 UTC (rev 
33543)
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2009, Michael Lotz, mmlr@xxxxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _LOCKS_H_
+#define _LOCKS_H_
+
+#include <OS.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mutex {
+       int32   benaphore;
+       sem_id  semaphore;
+} mutex;
+
+status_t       mutex_init(mutex *lock, const char *name);
+void           mutex_destroy(mutex *lock);
+status_t       mutex_lock(mutex *lock);
+void           mutex_unlock(mutex *lock);
+
+
+typedef struct rw_lock {
+       const char *                    name;
+       mutex                                   lock;
+       struct rw_lock_waiter * waiters;
+       struct rw_lock_waiter * last_waiter;
+       thread_id                               holder;
+       int32                                   reader_count;
+       int32                                   writer_count;
+       int32                                   owner_count;
+} rw_lock;
+
+status_t       rw_lock_init(rw_lock *lock, const char *name);
+void           rw_lock_destroy(rw_lock *lock);
+status_t       rw_lock_read_lock(rw_lock *lock);
+status_t       rw_lock_read_unlock(rw_lock *lock);
+status_t       rw_lock_write_lock(rw_lock *lock);
+status_t       rw_lock_write_unlock(rw_lock *lock);
+
+#ifdef __cplusplus
+} // extern "C"
+
+
+#include <AutoLocker.h>
+
+class MutexLocking {
+public:
+       inline bool Lock(struct mutex *lock)
+       {
+               return mutex_lock(lock) == B_OK;
+       }
+
+       inline void Unlock(struct mutex *lock)
+       {
+               mutex_unlock(lock);
+       }
+};
+
+
+class RWLockReadLocking {
+public:
+       inline bool Lock(struct rw_lock *lock)
+       {
+               return rw_lock_read_lock(lock) == B_OK;
+       }
+
+       inline void Unlock(struct rw_lock *lock)
+       {
+               rw_lock_read_unlock(lock);
+       }
+};
+
+
+class RWLockWriteLocking {
+public:
+       inline bool Lock(struct rw_lock *lock)
+       {
+               return rw_lock_write_lock(lock) == B_OK;
+       }
+
+       inline void Unlock(struct rw_lock *lock)
+       {
+               rw_lock_write_unlock(lock);
+       }
+};
+
+
+typedef AutoLocker<mutex, MutexLocking> MutexLocker;
+typedef AutoLocker<rw_lock, RWLockReadLocking> ReadLocker;
+typedef AutoLocker<rw_lock, RWLockWriteLocking> WriteLocker;
+
+#endif // __cplusplus
+
+#endif // _LOCKS_H_

Modified: haiku/trunk/src/system/libroot/os/Jamfile
===================================================================
--- haiku/trunk/src/system/libroot/os/Jamfile   2009-10-12 03:17:17 UTC (rev 
33542)
+++ haiku/trunk/src/system/libroot/os/Jamfile   2009-10-12 11:19:33 UTC (rev 
33543)
@@ -17,6 +17,7 @@
        fs_query.cpp
        fs_volume.c
        image.cpp
+       locks.cpp
        parsedate.cpp
        port.c
        scheduler.c

Added: haiku/trunk/src/system/libroot/os/locks.cpp
===================================================================
--- haiku/trunk/src/system/libroot/os/locks.cpp                         (rev 0)
+++ haiku/trunk/src/system/libroot/os/locks.cpp 2009-10-12 11:19:33 UTC (rev 
33543)
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2009, Michael Lotz, mmlr@xxxxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+#include <locks.h>
+#include <syscalls.h>
+
+#include <OS.h>
+
+
+status_t
+mutex_init(mutex *lock, const char *name)
+{
+       if (lock == NULL || name == NULL)
+               return B_BAD_VALUE;
+
+       lock->benaphore = 0;
+       lock->semaphore = create_sem(0, name);
+       if (lock->semaphore < 0)
+               return lock->semaphore;
+
+       return B_OK;
+}
+
+
+void
+mutex_destroy(mutex *lock)
+{
+       delete_sem(lock->semaphore);
+}
+
+
+status_t
+mutex_lock(mutex *lock)
+{
+       if (atomic_add(&lock->benaphore, 1) == 0)
+               return B_OK;
+
+       status_t result;
+       do {
+               result = acquire_sem(lock->semaphore);
+       } while (result == B_INTERRUPTED);
+
+       return result;
+}
+
+
+void
+mutex_unlock(mutex *lock)
+{
+       if (atomic_add(&lock->benaphore, -1) != 1)
+               release_sem(lock->semaphore);
+}
+
+
+typedef struct rw_lock_waiter {
+       rw_lock_waiter *        next;
+       thread_id                       thread;
+       bool                            writer;
+} rw_lock_waiter;
+
+
+static status_t
+rw_lock_wait(rw_lock *lock, bool writer)
+{
+       rw_lock_waiter waiter;
+       waiter.thread = find_thread(NULL);
+       waiter.next = NULL;
+       waiter.writer = writer;
+
+       if (lock->waiters != NULL)
+               lock->last_waiter->next = &waiter;
+       else
+               lock->waiters = &waiter;
+
+       lock->last_waiter = &waiter;
+
+       // the rw_lock is locked when entering, release it before blocking
+       mutex_unlock(&lock->lock);
+
+       status_t result;
+       do {
+               result = _kern_block_thread(0, 0);
+       } while (result == B_INTERRUPTED);
+
+       // and lock it again before returning
+       mutex_lock(&lock->lock);
+       return result;
+}
+
+
+static void
+rw_lock_unblock(rw_lock *lock)
+{
+       // this is called locked
+       if (lock->holder >= 0)
+               return;
+
+       rw_lock_waiter *waiter = lock->waiters;
+       if (waiter == NULL)
+               return;
+
+       if (waiter->writer) {
+               if (lock->reader_count > 0)
+                       return;
+
+               lock->waiters = waiter->next;
+               lock->holder = waiter->thread;
+               _kern_unblock_thread(waiter->thread, B_OK);
+               return;
+       }
+
+       while (waiter != NULL && !waiter->writer) {
+               lock->reader_count++;
+               lock->waiters = waiter->next;
+               _kern_unblock_thread(waiter->thread, B_OK);
+               waiter = lock->waiters;
+       }
+}
+
+
+status_t
+rw_lock_init(rw_lock *lock, const char *name)
+{
+       lock->name = name;
+       lock->waiters = NULL;
+       lock->holder = -1;
+       lock->reader_count = 0;
+       lock->writer_count = 0;
+       lock->owner_count = 0;
+       return mutex_init(&lock->lock, name);
+}
+
+
+void
+rw_lock_destroy(rw_lock *lock)
+{
+       mutex_lock(&lock->lock);
+
+       rw_lock_waiter *waiter = lock->waiters;
+       while (waiter != NULL) {
+               _kern_unblock_thread(waiter->thread, B_ERROR);
+               waiter = waiter->next;
+       }
+
+       mutex_destroy(&lock->lock);
+}
+
+
+status_t
+rw_lock_read_lock(rw_lock *lock)
+{
+       MutexLocker locker(lock->lock);
+
+       if (lock->writer_count == 0) {
+               lock->reader_count++;
+               return B_OK;
+       }
+
+       if (lock->holder == find_thread(NULL)) {
+               lock->owner_count++;
+               return B_OK;
+       }
+
+       return rw_lock_wait(lock, false);
+}
+
+
+status_t
+rw_lock_read_unlock(rw_lock *lock)
+{
+       MutexLocker locker(lock->lock);
+
+       if (lock->holder == find_thread(NULL)) {
+               if (--lock->owner_count > 0)
+                       return B_OK;
+
+               // this originally has been a write lock
+               lock->writer_count--;
+               lock->holder = -1;
+
+               rw_lock_unblock(lock);
+               return B_OK;
+       }
+
+       if (lock->reader_count <= 0) {
+               debugger("rw_lock not read locked");
+               return B_ERROR;
+       }
+
+       lock->reader_count--;
+       rw_lock_unblock(lock);
+       return B_OK;
+}
+
+
+status_t
+rw_lock_write_lock(rw_lock *lock)
+{
+       MutexLocker locker(lock->lock);
+
+       if (lock->reader_count == 0 && lock->writer_count == 0) {
+               lock->writer_count++;
+               lock->holder = find_thread(NULL);
+               lock->owner_count = 1;
+               return B_OK;
+       }
+
+       if (lock->holder == find_thread(NULL)) {
+               lock->owner_count++;
+               return B_OK;
+       }
+
+       lock->writer_count++;
+
+       status_t result = rw_lock_wait(lock, true);
+       if (result != B_OK)
+               return result;
+
+       if (lock->holder != find_thread(NULL)) {
+               debugger("write locked but holder not set");
+               return B_ERROR;
+       }
+
+       lock->owner_count = 1;
+       return B_OK;
+}
+
+
+status_t
+rw_lock_write_unlock(rw_lock *lock)
+{
+       MutexLocker locker(lock->lock);
+
+       if (lock->holder != find_thread(NULL)) {
+               debugger("rw_lock not write locked");
+               return B_ERROR;
+       }
+
+       if (--lock->owner_count > 0)
+               return B_OK;
+
+       lock->writer_count--;
+       lock->holder = -1;
+       rw_lock_unblock(lock);
+       return B_OK;
+}


Other related posts: