If `join-thread' timeout, the thread mutex is not unlocked, resulting in deadlock to the next call to it or deadlock of the thread itself when it terminates.
Thus, always unlock the mutex. Fix: #55356 * module/ice-9/threads.scm (join-thread): Always unlock thread mutex. * test-suite/tests/threads.test (join-thread): New test to ensure the mutex is released --- module/ice-9/threads.scm | 4 +++- test-suite/tests/threads.test | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/module/ice-9/threads.scm b/module/ice-9/threads.scm index 048d8b085..a1e43b9fa 100644 --- a/module/ice-9/threads.scm +++ b/module/ice-9/threads.scm @@ -204,7 +204,9 @@ terminates, unless the target @var{thread} has already terminated." (wait-condition-variable cv mutex timeout) (wait-condition-variable cv mutex)) (lp)) - (else timeoutval)))))) + (else + (unlock-mutex mutex) + timeoutval)))))) (define* (try-mutex mutex) "Try to lock @var{mutex}. If the mutex is already locked, return diff --git a/test-suite/tests/threads.test b/test-suite/tests/threads.test index efdf36db2..af8c8c75b 100644 --- a/test-suite/tests/threads.test +++ b/test-suite/tests/threads.test @@ -332,7 +332,18 @@ (sleep 2) (system-async-mark aproc) (join-thread other-thread))) - #t)) + #t) + + (pass-if "do not throw exception if trying to join after timeout" + (let ((other-thread (begin-thread (pause)))) + (dynamic-wind + (const #f) + (lambda () + (join-thread other-thread 1) + (join-thread other-thread 1) + #t) + (lambda () + (cancel-thread other-thread)))))) ;; ;; thread cancellation -- 2.41.0