[haiku-commits] Change in haiku[master]: kernel/locks: Implement lock switching for recursive_lock.

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 30 May 2020 00:02:35 +0000

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

Other related posts:

  • » [haiku-commits] Change in haiku[master]: kernel/locks: Implement lock switching for recursive_lock. - Gerrit