From Michael Lotz <mmlr@xxxxxxxx>:
Michael Lotz has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/2834 ;)
Change subject: kernel/locks: Implement lock switching for recursive_lock.
......................................................................
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.
---
M headers/private/kernel/lock.h
M src/system/kernel/locks/lock.cpp
2 files changed, 168 insertions(+), 4 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/34/2834/1
diff --git a/headers/private/kernel/lock.h b/headers/private/kernel/lock.h
index 770c3cb..92d0dda 100644
--- a/headers/private/kernel/lock.h
+++ b/headers/private/kernel/lock.h
@@ -126,6 +126,19 @@
extern status_t recursive_lock_lock(recursive_lock *lock);
extern status_t recursive_lock_trylock(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 void rw_lock_init(rw_lock* lock, const char* name);
diff --git a/src/system/kernel/locks/lock.cpp b/src/system/kernel/locks/lock.cpp
index 2176b3d..c6d5bcd 100644
--- a/src/system/kernel/locks/lock.cpp
+++ b/src/system/kernel/locks/lock.cpp
@@ -56,9 +56,7 @@
void
recursive_lock_init(recursive_lock *lock, const char *name)
{
- mutex_init(&lock->lock, name != NULL ? name : "recursive lock");
- RECURSIVE_LOCK_HOLDER(lock) = -1;
- lock->recursion = 0;
+ recursive_lock_init_etc(lock, name, 0);
}
@@ -66,7 +64,9 @@
recursive_lock_init_etc(recursive_lock *lock, const char *name, uint32 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;
}
@@ -147,6 +147,151 @@
}
+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 -
@@ -1002,4 +1147,10 @@
"<lock>\n"
"Prints info about the specified rw lock.\n"
" <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);
}
--
To view, visit https://review.haiku-os.org/c/haiku/+/2834
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: Ibeeae1b42c543d925dec61a3b257e1f3df7f8934
Gerrit-Change-Number: 2834
Gerrit-PatchSet: 1
Gerrit-Owner: Michael Lotz <mmlr@xxxxxxxx>
Gerrit-MessageType: newchange