kernel/locks: Implement lock switching for recursive_lock.
This allows switching from another recursive_lock, mutex or read-locked rw_lock analogous to the switching possibilities already in mutex. With this, recursive_locks can be used in more complex situations where previously only mutexes would work. Also add debugger command to dump a recursive_lock. Change-Id: Ibeeae1b42c543d925dec61a3b257e1f3df7f8934 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2834 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
38963e7596
commit
57656b93b6
@@ -126,6 +126,19 @@ extern void recursive_lock_destroy(recursive_lock *lock);
|
|||||||
extern status_t recursive_lock_lock(recursive_lock *lock);
|
extern status_t recursive_lock_lock(recursive_lock *lock);
|
||||||
extern status_t recursive_lock_trylock(recursive_lock *lock);
|
extern status_t recursive_lock_trylock(recursive_lock *lock);
|
||||||
extern void recursive_lock_unlock(recursive_lock *lock);
|
extern void recursive_lock_unlock(recursive_lock *lock);
|
||||||
|
extern status_t recursive_lock_switch_lock(recursive_lock* from,
|
||||||
|
recursive_lock* to);
|
||||||
|
// Unlocks "from" and locks "to" such that unlocking and starting to wait
|
||||||
|
// for the lock is atomic. I.e. if "from" guards the object "to" belongs
|
||||||
|
// to, the operation is safe as long as "from" is held while destroying
|
||||||
|
// "to".
|
||||||
|
extern status_t recursive_lock_switch_from_mutex(mutex* from,
|
||||||
|
recursive_lock* to);
|
||||||
|
// Like recursive_lock_switch_lock(), just for switching from a mutex.
|
||||||
|
extern status_t recursive_lock_switch_from_read_lock(rw_lock* from,
|
||||||
|
recursive_lock* to);
|
||||||
|
// Like recursive_lock_switch_lock(), just for switching from a read-locked
|
||||||
|
// rw_lock.
|
||||||
extern int32 recursive_lock_get_recursion(recursive_lock *lock);
|
extern int32 recursive_lock_get_recursion(recursive_lock *lock);
|
||||||
|
|
||||||
extern void rw_lock_init(rw_lock* lock, const char* name);
|
extern void rw_lock_init(rw_lock* lock, const char* name);
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ recursive_lock_get_recursion(recursive_lock *lock)
|
|||||||
void
|
void
|
||||||
recursive_lock_init(recursive_lock *lock, const char *name)
|
recursive_lock_init(recursive_lock *lock, const char *name)
|
||||||
{
|
{
|
||||||
mutex_init(&lock->lock, name != NULL ? name : "recursive lock");
|
recursive_lock_init_etc(lock, name, 0);
|
||||||
RECURSIVE_LOCK_HOLDER(lock) = -1;
|
|
||||||
lock->recursion = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -66,7 +64,9 @@ void
|
|||||||
recursive_lock_init_etc(recursive_lock *lock, const char *name, uint32 flags)
|
recursive_lock_init_etc(recursive_lock *lock, const char *name, uint32 flags)
|
||||||
{
|
{
|
||||||
mutex_init_etc(&lock->lock, name != NULL ? name : "recursive lock", flags);
|
mutex_init_etc(&lock->lock, name != NULL ? name : "recursive lock", flags);
|
||||||
RECURSIVE_LOCK_HOLDER(lock) = -1;
|
#if !KDEBUG
|
||||||
|
lock->holder = -1;
|
||||||
|
#endif
|
||||||
lock->recursion = 0;
|
lock->recursion = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +147,151 @@ recursive_lock_unlock(recursive_lock *lock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
recursive_lock_switch_lock(recursive_lock* from, recursive_lock* to)
|
||||||
|
{
|
||||||
|
#if KDEBUG
|
||||||
|
if (!gKernelStartup && !are_interrupts_enabled()) {
|
||||||
|
panic("recursive_lock_switch_lock(): called with interrupts "
|
||||||
|
"disabled for locks %p, %p", from, to);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (--from->recursion > 0)
|
||||||
|
return recursive_lock_lock(to);
|
||||||
|
|
||||||
|
#if !KDEBUG
|
||||||
|
from->holder = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
thread_id thread = thread_get_current_thread_id();
|
||||||
|
|
||||||
|
if (thread == RECURSIVE_LOCK_HOLDER(to)) {
|
||||||
|
to->recursion++;
|
||||||
|
mutex_unlock(&from->lock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t status = mutex_switch_lock(&from->lock, &to->lock);
|
||||||
|
if (status != B_OK) {
|
||||||
|
from->recursion++;
|
||||||
|
#if !KDEBUG
|
||||||
|
from->holder = thread;
|
||||||
|
#endif
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !KDEBUG
|
||||||
|
to->holder = thread;
|
||||||
|
#endif
|
||||||
|
to->recursion++;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
recursive_lock_switch_from_mutex(mutex* from, recursive_lock* to)
|
||||||
|
{
|
||||||
|
#if KDEBUG
|
||||||
|
if (!gKernelStartup && !are_interrupts_enabled()) {
|
||||||
|
panic("recursive_lock_switch_from_mutex(): called with interrupts "
|
||||||
|
"disabled for locks %p, %p", from, to);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
thread_id thread = thread_get_current_thread_id();
|
||||||
|
|
||||||
|
if (thread == RECURSIVE_LOCK_HOLDER(to)) {
|
||||||
|
to->recursion++;
|
||||||
|
mutex_unlock(from);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t status = mutex_switch_lock(from, &to->lock);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
#if !KDEBUG
|
||||||
|
to->holder = thread;
|
||||||
|
#endif
|
||||||
|
to->recursion++;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
recursive_lock_switch_from_read_lock(rw_lock* from, recursive_lock* to)
|
||||||
|
{
|
||||||
|
#if KDEBUG
|
||||||
|
if (!gKernelStartup && !are_interrupts_enabled()) {
|
||||||
|
panic("recursive_lock_switch_from_read_lock(): called with interrupts "
|
||||||
|
"disabled for locks %p, %p", from, to);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
thread_id thread = thread_get_current_thread_id();
|
||||||
|
|
||||||
|
if (thread != RECURSIVE_LOCK_HOLDER(to)) {
|
||||||
|
status_t status = mutex_switch_from_read_lock(from, &to->lock);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
#if !KDEBUG
|
||||||
|
to->holder = thread;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if KDEBUG_RW_LOCK_DEBUG
|
||||||
|
_rw_lock_write_unlock(from);
|
||||||
|
#else
|
||||||
|
int32 oldCount = atomic_add(&from->count, -1);
|
||||||
|
if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
|
||||||
|
_rw_lock_read_unlock(from);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
to->recursion++;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
dump_recursive_lock_info(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
print_debugger_command_usage(argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_lock* lock = (recursive_lock*)parse_expression(argv[1]);
|
||||||
|
|
||||||
|
if (!IS_KERNEL_ADDRESS(lock)) {
|
||||||
|
kprintf("invalid address: %p\n", lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintf("recrusive_lock %p:\n", lock);
|
||||||
|
kprintf(" mutex: %p\n", &lock->lock);
|
||||||
|
kprintf(" name: %s\n", lock->lock.name);
|
||||||
|
kprintf(" flags: 0x%x\n", lock->lock.flags);
|
||||||
|
#if KDEBUG
|
||||||
|
kprintf(" holder: %" B_PRId32 "\n", lock->lock.holder);
|
||||||
|
#else
|
||||||
|
kprintf(" holder: %" B_PRId32 "\n", lock->holder);
|
||||||
|
#endif
|
||||||
|
kprintf(" recursion: %d\n", lock->recursion);
|
||||||
|
|
||||||
|
kprintf(" waiting threads:");
|
||||||
|
mutex_waiter* waiter = lock->lock.waiters;
|
||||||
|
while (waiter != NULL) {
|
||||||
|
kprintf(" %" B_PRId32, waiter->thread->id);
|
||||||
|
waiter = waiter->next;
|
||||||
|
}
|
||||||
|
kputs("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -1002,4 +1147,10 @@ lock_debug_init()
|
|||||||
"<lock>\n"
|
"<lock>\n"
|
||||||
"Prints info about the specified rw lock.\n"
|
"Prints info about the specified rw lock.\n"
|
||||||
" <lock> - pointer to the rw lock to print the info for.\n", 0);
|
" <lock> - pointer to the rw lock to print the info for.\n", 0);
|
||||||
|
add_debugger_command_etc("recursivelock", &dump_recursive_lock_info,
|
||||||
|
"Dump info about a recursive lock",
|
||||||
|
"<lock>\n"
|
||||||
|
"Prints info about the specified recursive lock.\n"
|
||||||
|
" <lock> - pointer to the recursive lock to print the info for.\n",
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user