* The rw_lock is now able to nest read/write locks when you have a write lock.
It follows the semantics of the BFS R/W lock, though, that is, if you unlock your write lock before the read locks, the read locks effectively become write locks, too. * Added a mutex_transfer_lock() function that will allow you to unlock a mutex in a different thread than the one which locked it (only matters if KDEBUG is enabled, though). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26316 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -993,6 +993,7 @@
|
|||||||
#define mutex_lock fssh_mutex_lock
|
#define mutex_lock fssh_mutex_lock
|
||||||
#define mutex_trylock fssh_mutex_trylock
|
#define mutex_trylock fssh_mutex_trylock
|
||||||
#define mutex_unlock fssh_mutex_unlock
|
#define mutex_unlock fssh_mutex_unlock
|
||||||
|
#define mutex_transfer_lock fssh_mutex_transfer_lock
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ typedef struct fssh_recursive_lock {
|
|||||||
|
|
||||||
typedef struct fssh_rw_lock {
|
typedef struct fssh_rw_lock {
|
||||||
fssh_sem_id sem;
|
fssh_sem_id sem;
|
||||||
|
fssh_thread_id holder;
|
||||||
int32_t count;
|
int32_t count;
|
||||||
} fssh_rw_lock;
|
} fssh_rw_lock;
|
||||||
|
|
||||||
@@ -75,6 +76,7 @@ extern void fssh_mutex_destroy(fssh_mutex* lock);
|
|||||||
extern fssh_status_t fssh_mutex_lock(fssh_mutex* lock);
|
extern fssh_status_t fssh_mutex_lock(fssh_mutex* lock);
|
||||||
extern fssh_status_t fssh_mutex_trylock(fssh_mutex* lock);
|
extern fssh_status_t fssh_mutex_trylock(fssh_mutex* lock);
|
||||||
extern void fssh_mutex_unlock(fssh_mutex* lock);
|
extern void fssh_mutex_unlock(fssh_mutex* lock);
|
||||||
|
extern void fssh_mutex_transfer_lock(fssh_mutex* lock, fssh_thread_id thread);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ typedef struct rw_lock {
|
|||||||
thread_id holder;
|
thread_id holder;
|
||||||
int32 reader_count;
|
int32 reader_count;
|
||||||
int32 writer_count;
|
int32 writer_count;
|
||||||
|
int32 owner_count;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
} rw_lock;
|
} rw_lock;
|
||||||
|
|
||||||
@@ -159,6 +160,15 @@ mutex_unlock(mutex* lock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
mutex_transfer_lock(mutex* lock, thread_id thread)
|
||||||
|
{
|
||||||
|
#ifdef KDEBUG
|
||||||
|
lock->holder = thread;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern void lock_debug_init();
|
extern void lock_debug_init();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ rw_lock_unblock(rw_lock* lock)
|
|||||||
lock->waiters->last = waiter->last;
|
lock->waiters->last = waiter->last;
|
||||||
|
|
||||||
lock->holder = waiter->thread->id;
|
lock->holder = waiter->thread->id;
|
||||||
|
|
||||||
// unblock thread
|
// unblock thread
|
||||||
thread_unblock_locked(waiter->thread, B_OK);
|
thread_unblock_locked(waiter->thread, B_OK);
|
||||||
}
|
}
|
||||||
@@ -221,6 +221,7 @@ rw_lock_init(rw_lock* lock, const char* name)
|
|||||||
lock->holder = -1;
|
lock->holder = -1;
|
||||||
lock->reader_count = 0;
|
lock->reader_count = 0;
|
||||||
lock->writer_count = 0;
|
lock->writer_count = 0;
|
||||||
|
lock->owner_count = 0;
|
||||||
lock->flags = 0;
|
lock->flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +234,7 @@ rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags)
|
|||||||
lock->holder = -1;
|
lock->holder = -1;
|
||||||
lock->reader_count = 0;
|
lock->reader_count = 0;
|
||||||
lock->writer_count = 0;
|
lock->writer_count = 0;
|
||||||
|
lock->owner_count = 0;
|
||||||
lock->flags = flags & RW_LOCK_FLAG_CLONE_NAME;
|
lock->flags = flags & RW_LOCK_FLAG_CLONE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +286,10 @@ rw_lock_read_lock(rw_lock* lock)
|
|||||||
lock->reader_count++;
|
lock->reader_count++;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
if (lock->holder == thread_get_current_thread_id()) {
|
||||||
|
lock->owner_count++;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
return rw_lock_wait(lock, false);
|
return rw_lock_wait(lock, false);
|
||||||
}
|
}
|
||||||
@@ -294,6 +300,18 @@ rw_lock_read_unlock(rw_lock* lock)
|
|||||||
{
|
{
|
||||||
InterruptsSpinLocker locker(thread_spinlock);
|
InterruptsSpinLocker locker(thread_spinlock);
|
||||||
|
|
||||||
|
if (lock->holder == thread_get_current_thread_id()) {
|
||||||
|
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) {
|
if (lock->reader_count <= 0) {
|
||||||
panic("rw_lock_read_unlock(): lock %p not read-locked", lock);
|
panic("rw_lock_read_unlock(): lock %p not read-locked", lock);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -302,7 +320,6 @@ rw_lock_read_unlock(rw_lock* lock)
|
|||||||
lock->reader_count--;
|
lock->reader_count--;
|
||||||
|
|
||||||
rw_lock_unblock(lock);
|
rw_lock_unblock(lock);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,11 +332,22 @@ rw_lock_write_lock(rw_lock* lock)
|
|||||||
if (lock->reader_count == 0 && lock->writer_count == 0) {
|
if (lock->reader_count == 0 && lock->writer_count == 0) {
|
||||||
lock->writer_count++;
|
lock->writer_count++;
|
||||||
lock->holder = thread_get_current_thread_id();
|
lock->holder = thread_get_current_thread_id();
|
||||||
|
lock->owner_count = 1;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
if (lock->holder == thread_get_current_thread_id()) {
|
||||||
|
lock->owner_count++;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock->writer_count++;
|
lock->writer_count++;
|
||||||
return rw_lock_wait(lock, true);
|
|
||||||
|
status_t status = rw_lock_wait(lock, true);
|
||||||
|
if (status == B_OK) {
|
||||||
|
lock->holder = thread_get_current_thread_id();
|
||||||
|
lock->owner_count = 1;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -333,6 +361,8 @@ rw_lock_write_unlock(rw_lock* lock)
|
|||||||
lock);
|
lock);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
if (--lock->owner_count > 0)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
lock->writer_count--;
|
lock->writer_count--;
|
||||||
lock->holder = -1;
|
lock->holder = -1;
|
||||||
|
|||||||
@@ -176,6 +176,13 @@ fssh_mutex_unlock(fssh_mutex *mutex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
fssh_mutex_transfer_lock(fssh_mutex *mutex, fssh_thread_id thread)
|
||||||
|
{
|
||||||
|
mutex->holder = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -188,6 +195,9 @@ fssh_rw_lock_init(fssh_rw_lock *lock, const char *name)
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
name = "r/w lock";
|
name = "r/w lock";
|
||||||
|
|
||||||
|
lock->count = 0;
|
||||||
|
lock->holder = -1;
|
||||||
|
|
||||||
lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name);
|
lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name);
|
||||||
if (lock->sem < FSSH_B_OK)
|
if (lock->sem < FSSH_B_OK)
|
||||||
fssh_panic("could not create r/w lock");
|
fssh_panic("could not create r/w lock");
|
||||||
@@ -214,6 +224,11 @@ fssh_rw_lock_destroy(fssh_rw_lock *lock)
|
|||||||
extern "C" fssh_status_t
|
extern "C" fssh_status_t
|
||||||
fssh_rw_lock_read_lock(fssh_rw_lock *lock)
|
fssh_rw_lock_read_lock(fssh_rw_lock *lock)
|
||||||
{
|
{
|
||||||
|
if (lock->holder == fssh_find_thread(NULL)) {
|
||||||
|
lock->count++;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
return fssh_acquire_sem(lock->sem);
|
return fssh_acquire_sem(lock->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +236,9 @@ fssh_rw_lock_read_lock(fssh_rw_lock *lock)
|
|||||||
extern "C" fssh_status_t
|
extern "C" fssh_status_t
|
||||||
fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
|
fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
|
||||||
{
|
{
|
||||||
|
if (lock->holder == fssh_find_thread(NULL) && --lock->count > 0)
|
||||||
|
return FSSH_B_OK;
|
||||||
|
|
||||||
return fssh_release_sem(lock->sem);
|
return fssh_release_sem(lock->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,13 +246,29 @@ fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
|
|||||||
extern "C" fssh_status_t
|
extern "C" fssh_status_t
|
||||||
fssh_rw_lock_write_lock(fssh_rw_lock *lock)
|
fssh_rw_lock_write_lock(fssh_rw_lock *lock)
|
||||||
{
|
{
|
||||||
return fssh_acquire_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0, 0);
|
if (lock->holder == fssh_find_thread(NULL)) {
|
||||||
|
lock->count++;
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
fssh_status_t status = fssh_acquire_sem_etc(lock->sem, FSSH_RW_MAX_READERS,
|
||||||
|
0, 0);
|
||||||
|
if (status == FSSH_B_OK) {
|
||||||
|
lock->holder = fssh_find_thread(NULL);
|
||||||
|
lock->count = 1;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" fssh_status_t
|
extern "C" fssh_status_t
|
||||||
fssh_rw_lock_write_unlock(fssh_rw_lock *lock)
|
fssh_rw_lock_write_unlock(fssh_rw_lock *lock)
|
||||||
{
|
{
|
||||||
|
if (--lock->count > 0)
|
||||||
|
return FSSH_B_OK;
|
||||||
|
|
||||||
|
lock->holder = -1;
|
||||||
|
|
||||||
return fssh_release_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0);
|
return fssh_release_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user