* 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.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34364 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-11-30 10:29:51 +00:00
parent c598298047
commit 258b34c594
10 changed files with 519 additions and 497 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ typedef struct lazy_mutex {
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);
+7 -1
View File
@@ -5,6 +5,8 @@ UsePrivateHeaders kernel ;
# 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 @@ MergeObject os_main.o :
fs_query.cpp
fs_volume.c
image.cpp
locks.cpp
parsedate.cpp
port.c
scheduler.c
@@ -29,6 +30,11 @@ MergeObject os_main.o :
syscalls.S
wait_for_objects.cpp
# locks
mutex.cpp
recursive_lock.cpp
rw_lock.cpp
KMessage.cpp
;
-491
View File
@@ -1,491 +0,0 @@
/*
* Copyright 2009, Michael Lotz, [email protected].
* Distributed under the terms of the MIT License.
*/
/*
* Copyright 2008-2009, Ingo Weinhold, [email protected].
* Copyright 2002-2009, Axel Dörfler, [email protected]. 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 <syscalls.h>
#include <user_thread.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);
}
}
// #pragma mark - R/W lock
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;
}
// #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);
}
}
+164
View File
@@ -0,0 +1,164 @@
/*
* Copyright 2009, Michael Lotz, [email protected].
* Copyright 2008-2009, Ingo Weinhold, [email protected].
* Copyright 2002-2009, Axel Dörfler, [email protected]. 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);
}
}
@@ -0,0 +1,138 @@
/*
* Copyright 2009, Michael Lotz, [email protected].
* Copyright 2008-2009, Ingo Weinhold, [email protected].
* Copyright 2002-2009, Axel Dörfler, [email protected]. 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);
}
}
+207
View File
@@ -0,0 +1,207 @@
/*
* Copyright 2009, Michael Lotz, [email protected].
* 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;
}
+2 -1
View File
@@ -24,7 +24,8 @@ StaticLibrary libruntime_loader.a :
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
@@ -10,7 +10,6 @@ StaticLibrary libruntime_loader_$(TARGET_ARCH).a :
:
<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
@@ -10,7 +10,6 @@ StaticLibrary libruntime_loader_$(TARGET_ARCH).a :
:
<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
@@ -10,7 +10,6 @@ StaticLibrary libruntime_loader_$(TARGET_ARCH).a :
:
<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