Author: bonefish Date: 2009-11-30 11:29:51 +0100 (Mon, 30 Nov 2009) New Revision: 34364 Changeset: http://dev.haiku-os.org/changeset/34364/haiku Added: haiku/trunk/src/system/libroot/os/locks/ haiku/trunk/src/system/libroot/os/locks/mutex.cpp haiku/trunk/src/system/libroot/os/locks/recursive_lock.cpp haiku/trunk/src/system/libroot/os/locks/rw_lock.cpp Removed: haiku/trunk/src/system/libroot/os/locks.cpp Modified: haiku/trunk/headers/private/shared/locks.h haiku/trunk/src/system/libroot/os/Jamfile haiku/trunk/src/system/runtime_loader/Jamfile haiku/trunk/src/system/runtime_loader/arch/m68k/Jamfile haiku/trunk/src/system/runtime_loader/arch/ppc/Jamfile haiku/trunk/src/system/runtime_loader/arch/x86/Jamfile Log: * Fixed wrong parameter of lazy_mutex_destroy(). * Split locks.cpp into mutex.cpp, recursive_lock.cpp, and rw_lock.cpp (new subdirectory locks/). * runtime_loader no longer includes the rw_lock, allowing removal of the TLS dependency again. Modified: haiku/trunk/headers/private/shared/locks.h =================================================================== --- haiku/trunk/headers/private/shared/locks.h 2009-11-30 08:31:31 UTC (rev 34363) +++ haiku/trunk/headers/private/shared/locks.h 2009-11-30 10:29:51 UTC (rev 34364) @@ -30,7 +30,7 @@ status_t lazy_mutex_init(lazy_mutex *lock, const char *name); // name will not be cloned and must rename valid -void lazy_mutex_destroy(mutex *lock); +void lazy_mutex_destroy(lazy_mutex *lock); status_t lazy_mutex_lock(lazy_mutex *lock); void lazy_mutex_unlock(lazy_mutex *lock); Modified: haiku/trunk/src/system/libroot/os/Jamfile =================================================================== --- haiku/trunk/src/system/libroot/os/Jamfile 2009-11-30 08:31:31 UTC (rev 34363) +++ haiku/trunk/src/system/libroot/os/Jamfile 2009-11-30 10:29:51 UTC (rev 34364) @@ -5,6 +5,8 @@ # for util/KMessage.h UsePrivateHeaders libroot runtime_loader shared ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) locks ] ; + MergeObject os_main.o : area.c atomic.c @@ -17,7 +19,6 @@ fs_query.cpp fs_volume.c image.cpp - locks.cpp parsedate.cpp port.c scheduler.c @@ -29,6 +30,11 @@ syscalls.S wait_for_objects.cpp + # locks + mutex.cpp + recursive_lock.cpp + rw_lock.cpp + KMessage.cpp ; Copied: haiku/trunk/src/system/libroot/os/locks/mutex.cpp (from rev 34363, haiku/trunk/src/system/libroot/os/locks.cpp) =================================================================== --- haiku/trunk/src/system/libroot/os/locks/mutex.cpp (rev 0) +++ haiku/trunk/src/system/libroot/os/locks/mutex.cpp 2009-11-30 10:29:51 UTC (rev 34364) @@ -0,0 +1,164 @@ +/* + * Copyright 2009, Michael Lotz, mmlr@xxxxxxxxx + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Copyright 2002-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + + +#include <locks.h> + +#include <OS.h> + + +// #pragma mark - mutex + + +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); +} + + +// #pragma mark - lazy mutex + + +enum { + STATE_UNINITIALIZED = -1, + STATE_INITIALIZING = -2, + STATE_SPIN_LOCKED = -3, + STATE_SPIN_UNLOCKED = -4 +}; + + +static inline bool +lazy_mutex_ensure_init(lazy_mutex *lock) +{ + int32 value = atomic_test_and_set((vint32*)&lock->semaphore, + STATE_INITIALIZING, STATE_UNINITIALIZED); + + if (value >= 0) + return true; + + if (value == STATE_UNINITIALIZED) { + // we're the first -- perform the initialization + sem_id semaphore = create_sem(0, lock->name); + if (semaphore < 0) + semaphore = STATE_SPIN_UNLOCKED; + atomic_set((vint32*)&lock->semaphore, semaphore); + return semaphore >= 0; + } + + if (value == STATE_INITIALIZING) { + // someone else is initializing -- spin until that is done + while (atomic_get((vint32*)&lock->semaphore) == STATE_INITIALIZING) { + } + } + + return lock->semaphore >= 0; +} + + +status_t +lazy_mutex_init(lazy_mutex *lock, const char *name) +{ + if (lock == NULL || name == NULL) + return B_BAD_VALUE; + + lock->benaphore = 0; + lock->semaphore = STATE_UNINITIALIZED; + lock->name = name; + + return B_OK; +} + + +void +lazy_mutex_destroy(lazy_mutex *lock) +{ + if (lock->semaphore >= 0) + delete_sem(lock->semaphore); +} + + +status_t +lazy_mutex_lock(lazy_mutex *lock) +{ + if (atomic_add(&lock->benaphore, 1) == 0) + return B_OK; + + if (lazy_mutex_ensure_init(lock)) { + // acquire the semaphore + status_t result; + do { + result = acquire_sem(lock->semaphore); + } while (result == B_INTERRUPTED); + + return result; + } else { + // the semaphore creation failed -- so we use it like a spinlock instead + while (atomic_test_and_set((vint32*)&lock->semaphore, + STATE_SPIN_LOCKED, STATE_SPIN_UNLOCKED) + != STATE_SPIN_UNLOCKED) { + } + return B_OK; + } +} + + +void +lazy_mutex_unlock(lazy_mutex *lock) +{ + if (atomic_add(&lock->benaphore, -1) == 1) + return; + + if (lazy_mutex_ensure_init(lock)) { + // release the semaphore + release_sem(lock->semaphore); + } else { + // the semaphore creation failed -- so we use it like a spinlock instead + atomic_set((vint32*)&lock->semaphore, STATE_SPIN_UNLOCKED); + } +} Copied: haiku/trunk/src/system/libroot/os/locks/recursive_lock.cpp (from rev 34363, haiku/trunk/src/system/libroot/os/locks.cpp) =================================================================== --- haiku/trunk/src/system/libroot/os/locks/recursive_lock.cpp (rev 0) +++ haiku/trunk/src/system/libroot/os/locks/recursive_lock.cpp 2009-11-30 10:29:51 UTC (rev 34364) @@ -0,0 +1,138 @@ +/* + * Copyright 2009, Michael Lotz, mmlr@xxxxxxxxx + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Copyright 2002-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + + +#include <locks.h> + +#include <OS.h> + + +// #pragma mark - recursive lock + + +int32 +recursive_lock_get_recursion(recursive_lock *lock) +{ + if (lock->holder == find_thread(NULL)) + return lock->recursion; + + return -1; +} + + +status_t +recursive_lock_init(recursive_lock *lock, const char *name) +{ + lock->holder = -1; + lock->recursion = 0; + return mutex_init(&lock->lock, name != NULL ? name : "recursive lock"); +} + + +void +recursive_lock_destroy(recursive_lock *lock) +{ + if (lock == NULL) + return; + + mutex_destroy(&lock->lock); +} + + +status_t +recursive_lock_lock(recursive_lock *lock) +{ + thread_id thread = find_thread(NULL); + + if (thread != lock->holder) { + mutex_lock(&lock->lock); + lock->holder = thread; + } + + lock->recursion++; + return B_OK; +} + + +void +recursive_lock_unlock(recursive_lock *lock) +{ + if (find_thread(NULL) != lock->holder) { + debugger("recursive_lock unlocked by non-holder thread!\n"); + return; + } + + if (--lock->recursion == 0) { + lock->holder = -1; + mutex_unlock(&lock->lock); + } +} + + +// #pragma mark - lazy recursive lock + + +int32 +lazy_recursive_lock_get_recursion(lazy_recursive_lock *lock) +{ + if (lock->holder == find_thread(NULL)) + return lock->recursion; + + return -1; +} + + +status_t +lazy_recursive_lock_init(lazy_recursive_lock *lock, const char *name) +{ + lock->holder = -1; + lock->recursion = 0; + return lazy_mutex_init(&lock->lock, name != NULL ? name : "recursive lock"); +} + + +void +lazy_recursive_lock_destroy(lazy_recursive_lock *lock) +{ + if (lock == NULL) + return; + + lazy_mutex_destroy(&lock->lock); +} + + +status_t +lazy_recursive_lock_lock(lazy_recursive_lock *lock) +{ + thread_id thread = find_thread(NULL); + + if (thread != lock->holder) { + lazy_mutex_lock(&lock->lock); + lock->holder = thread; + } + + lock->recursion++; + return B_OK; +} + + +void +lazy_recursive_lock_unlock(lazy_recursive_lock *lock) +{ + if (find_thread(NULL) != lock->holder) { + debugger("lazy_recursive_lock unlocked by non-holder thread!\n"); + return; + } + + if (--lock->recursion == 0) { + lock->holder = -1; + lazy_mutex_unlock(&lock->lock); + } +} Copied: haiku/trunk/src/system/libroot/os/locks/rw_lock.cpp (from rev 34363, haiku/trunk/src/system/libroot/os/locks.cpp) =================================================================== --- haiku/trunk/src/system/libroot/os/locks/rw_lock.cpp (rev 0) +++ haiku/trunk/src/system/libroot/os/locks/rw_lock.cpp 2009-11-30 10:29:51 UTC (rev 34364) @@ -0,0 +1,207 @@ +/* + * Copyright 2009, Michael Lotz, mmlr@xxxxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include <locks.h> + +#include <OS.h> + +#include <syscalls.h> +#include <user_thread.h> + + +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 + get_user_thread()->wait_status = 1; + 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; +} Modified: haiku/trunk/src/system/runtime_loader/Jamfile =================================================================== --- haiku/trunk/src/system/runtime_loader/Jamfile 2009-11-30 08:31:31 UTC (rev 34363) +++ haiku/trunk/src/system/runtime_loader/Jamfile 2009-11-30 10:29:51 UTC (rev 34364) @@ -24,7 +24,8 @@ kernel_cpp.cpp KMessage.cpp : - <src!system!libroot!os>locks.o + <src!system!libroot!os>mutex.o + <src!system!libroot!os>recursive_lock.o <src!system!libroot!os>syscalls.o <src!system!libroot!os>sem.o Modified: haiku/trunk/src/system/runtime_loader/arch/m68k/Jamfile =================================================================== --- haiku/trunk/src/system/runtime_loader/arch/m68k/Jamfile 2009-11-30 08:31:31 UTC (rev 34363) +++ haiku/trunk/src/system/runtime_loader/arch/m68k/Jamfile 2009-11-30 10:29:51 UTC (rev 34364) @@ -10,7 +10,6 @@ : <src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o <src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o - <src!system!libroot!os!arch!$(TARGET_ARCH)>tls.o <src!system!libroot!posix!string!arch!$(TARGET_ARCH)>arch_string.o <src!system!libroot!posix!string!arch!$(TARGET_ARCH)>memset.o Modified: haiku/trunk/src/system/runtime_loader/arch/ppc/Jamfile =================================================================== --- haiku/trunk/src/system/runtime_loader/arch/ppc/Jamfile 2009-11-30 08:31:31 UTC (rev 34363) +++ haiku/trunk/src/system/runtime_loader/arch/ppc/Jamfile 2009-11-30 10:29:51 UTC (rev 34364) @@ -10,7 +10,6 @@ : <src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o <src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o - <src!system!libroot!os!arch!$(TARGET_ARCH)>tls.o <src!system!libroot!posix!string!arch!$(TARGET_ARCH)>memcpy.o <src!system!libroot!posix!string!arch!$(TARGET_ARCH)>memset.o Modified: haiku/trunk/src/system/runtime_loader/arch/x86/Jamfile =================================================================== --- haiku/trunk/src/system/runtime_loader/arch/x86/Jamfile 2009-11-30 08:31:31 UTC (rev 34363) +++ haiku/trunk/src/system/runtime_loader/arch/x86/Jamfile 2009-11-30 10:29:51 UTC (rev 34364) @@ -10,7 +10,6 @@ : <src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o <src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o - <src!system!libroot!os!arch!$(TARGET_ARCH)>tls.o # <src!system!libroot!posix!string>memcpy.o <src!system!libroot!posix!string!arch!$(TARGET_ARCH)>arch_string.o