mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Remove possible deadlock in scm_join_thread
* libguile/threads.c (scm_join_thread): Always recheck t->exited before calling block_self again, in case thread t has now exited. * test-suite/tests/threads.test (joining): New test.
This commit is contained in:
parent
3ed47d2203
commit
66f3b6c1b0
2 changed files with 40 additions and 11 deletions
|
@ -934,17 +934,14 @@ SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
|
||||||
scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
|
scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
|
||||||
|
|
||||||
t = SCM_I_THREAD_DATA (thread);
|
t = SCM_I_THREAD_DATA (thread);
|
||||||
if (!t->exited)
|
while (!t->exited)
|
||||||
{
|
{
|
||||||
while (1)
|
block_self (t->join_queue, thread, &thread_admin_mutex, NULL);
|
||||||
{
|
if (t->exited)
|
||||||
block_self (t->join_queue, thread, &thread_admin_mutex, NULL);
|
break;
|
||||||
if (t->exited)
|
scm_i_pthread_mutex_unlock (&thread_admin_mutex);
|
||||||
break;
|
SCM_TICK;
|
||||||
scm_i_pthread_mutex_unlock (&thread_admin_mutex);
|
scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
|
||||||
SCM_TICK;
|
|
||||||
scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res = t->result;
|
res = t->result;
|
||||||
|
|
||||||
|
|
|
@ -133,4 +133,36 @@
|
||||||
(lambda (n) (set! result (cons n result)))
|
(lambda (n) (set! result (cons n result)))
|
||||||
(lambda (n) (* 2 n))
|
(lambda (n) (* 2 n))
|
||||||
'(0 1 2 3 4 5))
|
'(0 1 2 3 4 5))
|
||||||
(equal? result '(10 8 6 4 2 0)))))))
|
(equal? result '(10 8 6 4 2 0)))))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; thread joining
|
||||||
|
;;
|
||||||
|
|
||||||
|
(with-test-prefix "joining"
|
||||||
|
|
||||||
|
;; scm_join_thread has a SCM_TICK in the middle of it, to
|
||||||
|
;; allow asyncs to run (including signal delivery). We used
|
||||||
|
;; to have a bug whereby if the joined thread terminated at
|
||||||
|
;; the same time as the joining thread is in this SCM_TICK,
|
||||||
|
;; scm_join_thread would not notice and would hang forever.
|
||||||
|
;; So in this test we are setting up the following sequence of
|
||||||
|
;; events.
|
||||||
|
;; T=0 other thread is created and starts running
|
||||||
|
;; T=2 main thread sets up an async that will sleep for 10 seconds
|
||||||
|
;; T=2 main thread calls join-thread, which will...
|
||||||
|
;; T=2 ...call the async, which starts sleeping
|
||||||
|
;; T=5 other thread finishes its work and terminates
|
||||||
|
;; T=7 async completes, main thread continues inside join-thread.
|
||||||
|
(pass-if "don't hang when joined thread terminates in SCM_TICK"
|
||||||
|
(let ((other-thread (make-thread sleep 5)))
|
||||||
|
(letrec ((delay-count 10)
|
||||||
|
(aproc (lambda ()
|
||||||
|
(set! delay-count (- delay-count 1))
|
||||||
|
(if (zero? delay-count)
|
||||||
|
(sleep 5)
|
||||||
|
(system-async-mark aproc)))))
|
||||||
|
(sleep 2)
|
||||||
|
(system-async-mark aproc)
|
||||||
|
(join-thread other-thread)))
|
||||||
|
#t))))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue