From 78b32dd026c23138d8102e48885f829e1acb5153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 8 Jul 2008 07:56:49 +0000 Subject: [PATCH] * 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 --- headers/private/fs_shell/fssh_api_wrapper.h | 1 + headers/private/fs_shell/fssh_lock.h | 2 ++ headers/private/kernel/lock.h | 10 ++++++ src/system/kernel/lock.cpp | 36 +++++++++++++++++++-- src/tools/fs_shell/lock.cpp | 36 ++++++++++++++++++++- 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/headers/private/fs_shell/fssh_api_wrapper.h b/headers/private/fs_shell/fssh_api_wrapper.h index bd4ac10d60..e7138e75a7 100644 --- a/headers/private/fs_shell/fssh_api_wrapper.h +++ b/headers/private/fs_shell/fssh_api_wrapper.h @@ -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 //////////////////////////////////////////////////////////////////////////////// diff --git a/headers/private/fs_shell/fssh_lock.h b/headers/private/fs_shell/fssh_lock.h index 816420d2e3..0c587aa198 100644 --- a/headers/private/fs_shell/fssh_lock.h +++ b/headers/private/fs_shell/fssh_lock.h @@ -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 } diff --git a/headers/private/kernel/lock.h b/headers/private/kernel/lock.h index 308dfeb323..75e2b69d8e 100644 --- a/headers/private/kernel/lock.h +++ b/headers/private/kernel/lock.h @@ -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 diff --git a/src/system/kernel/lock.cpp b/src/system/kernel/lock.cpp index f8165249f0..83092bcfe5 100644 --- a/src/system/kernel/lock.cpp +++ b/src/system/kernel/lock.cpp @@ -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; diff --git a/src/tools/fs_shell/lock.cpp b/src/tools/fs_shell/lock.cpp index 0c031825d8..8b8ae72bd0 100644 --- a/src/tools/fs_shell/lock.cpp +++ b/src/tools/fs_shell/lock.cpp @@ -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); }