Subject: [PATCH] Fix possible deadlock.

From: Olivier Dion <[email-masked]>
Date: Sat, 5 Nov 2022 12:59:23 -0400

If we got interrupted while waiting on our condition variable, we unlock
the kernel mutex momentarily while executing asynchronous operations
before putting us back into the waiting queue.

However, we have to retry acquiring the mutex before getting back into
the queue, otherwise it's possible that we wait indefinitely since
nobody could be the owner for a while.

* libguile/threads.c (lock_mutex): Try acquring the mutex after signal
interruption.
---
 libguile/threads.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/libguile/threads.c b/libguile/threads.c
index 280d306bf..0f5cf2ed5 100644
--- a/libguile/threads.c
+++ b/libguile/threads.c
@@ -1022,14 +1022,7 @@ lock_mutex (enum scm_mutex_kind kind, struct scm_mutex *m,
 
         if (err == 0)
           {
-            if (scm_is_eq (m->owner, SCM_BOOL_F))
-              {
-                m->owner = current_thread->handle;
-                scm_i_pthread_mutex_unlock (&m->lock);
-                return SCM_BOOL_T;
-              }
-            else
-              continue;
+            goto maybe_acquire;
           }
         else if (err == ETIMEDOUT)
           {
@@ -1041,7 +1034,7 @@ lock_mutex (enum scm_mutex_kind kind, struct scm_mutex *m,
             scm_i_pthread_mutex_unlock (&m->lock);
             scm_async_tick ();
             scm_i_scm_pthread_mutex_lock (&m->lock);
-            continue;
+            goto maybe_acquire;
           }
         else
           {
@@ -1050,6 +1043,14 @@ lock_mutex (enum scm_mutex_kind kind, struct scm_mutex *m,
             errno = err;
             SCM_SYSERROR;
           }
+
+      maybe_acquire:
+        if (scm_is_eq (m->owner, SCM_BOOL_F))
+          {
+            m->owner = current_thread->handle;
+            scm_i_pthread_mutex_unlock (&m->lock);
+            return SCM_BOOL_T;
+          }
       }
 }
 #undef FUNC_NAME
-- 
2.38.0