* 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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user