* 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:
parent
f90a5e346d
commit
78b32dd026
@ -993,6 +993,7 @@
|
||||
#define mutex_lock fssh_mutex_lock
|
||||
#define mutex_trylock fssh_mutex_trylock
|
||||
#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 {
|
||||
fssh_sem_id sem;
|
||||
fssh_thread_id holder;
|
||||
int32_t count;
|
||||
} 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_trylock(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
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ typedef struct rw_lock {
|
||||
thread_id holder;
|
||||
int32 reader_count;
|
||||
int32 writer_count;
|
||||
int32 owner_count;
|
||||
uint32 flags;
|
||||
} 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();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -191,7 +191,7 @@ rw_lock_unblock(rw_lock* lock)
|
||||
lock->waiters->last = waiter->last;
|
||||
|
||||
lock->holder = waiter->thread->id;
|
||||
|
||||
|
||||
// unblock thread
|
||||
thread_unblock_locked(waiter->thread, B_OK);
|
||||
}
|
||||
@ -221,6 +221,7 @@ rw_lock_init(rw_lock* lock, const char* name)
|
||||
lock->holder = -1;
|
||||
lock->reader_count = 0;
|
||||
lock->writer_count = 0;
|
||||
lock->owner_count = 0;
|
||||
lock->flags = 0;
|
||||
}
|
||||
|
||||
@ -233,6 +234,7 @@ rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags)
|
||||
lock->holder = -1;
|
||||
lock->reader_count = 0;
|
||||
lock->writer_count = 0;
|
||||
lock->owner_count = 0;
|
||||
lock->flags = flags & RW_LOCK_FLAG_CLONE_NAME;
|
||||
}
|
||||
|
||||
@ -284,6 +286,10 @@ rw_lock_read_lock(rw_lock* lock)
|
||||
lock->reader_count++;
|
||||
return B_OK;
|
||||
}
|
||||
if (lock->holder == thread_get_current_thread_id()) {
|
||||
lock->owner_count++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return rw_lock_wait(lock, false);
|
||||
}
|
||||
@ -294,6 +300,18 @@ rw_lock_read_unlock(rw_lock* lock)
|
||||
{
|
||||
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) {
|
||||
panic("rw_lock_read_unlock(): lock %p not read-locked", lock);
|
||||
return B_BAD_VALUE;
|
||||
@ -302,7 +320,6 @@ rw_lock_read_unlock(rw_lock* lock)
|
||||
lock->reader_count--;
|
||||
|
||||
rw_lock_unblock(lock);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -315,11 +332,22 @@ rw_lock_write_lock(rw_lock* lock)
|
||||
if (lock->reader_count == 0 && lock->writer_count == 0) {
|
||||
lock->writer_count++;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
if (--lock->owner_count > 0)
|
||||
return B_OK;
|
||||
|
||||
lock->writer_count--;
|
||||
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 -
|
||||
|
||||
|
||||
@ -188,6 +195,9 @@ fssh_rw_lock_init(fssh_rw_lock *lock, const char *name)
|
||||
if (name == NULL)
|
||||
name = "r/w lock";
|
||||
|
||||
lock->count = 0;
|
||||
lock->holder = -1;
|
||||
|
||||
lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name);
|
||||
if (lock->sem < FSSH_B_OK)
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
@ -221,6 +236,9 @@ fssh_rw_lock_read_lock(fssh_rw_lock *lock)
|
||||
extern "C" fssh_status_t
|
||||
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);
|
||||
}
|
||||
|
||||
@ -228,13 +246,29 @@ fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
|
||||
extern "C" fssh_status_t
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user