* 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:
Axel Dörfler 2008-07-08 07:56:49 +00:00
parent f90a5e346d
commit 78b32dd026
5 changed files with 81 additions and 4 deletions

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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
}

View File

@ -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

View File

@ -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;

View File

@ -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);
}