mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
Fix two wait-condition-variable race conditions
* libguile/threads.c (timed_wait): When looping to reacquire mutex, check if mutex owner after dropping mutex to run asyncs when the reacquire is interrupted. Also for asyncs that interrupted the initial wait, just return #t directly, and allow the caller to loop. Fixes a deadlock in which a thread could have pending asyncs after dropping a mutex and which prevent it from going to wait on a cond, but then the broadcast comes while nobody is waiting and the mutex is dropped, then after reacquiring the mutex when we go to wait again, we wait forever. The correct thing to do is after reacquiring the mutex, to allow the application to check if waiting is appropriate.
This commit is contained in:
parent
8bd5dae8c3
commit
a9dc553893
1 changed files with 10 additions and 12 deletions
|
@ -1316,12 +1316,7 @@ timed_wait (enum scm_mutex_kind kind, struct scm_mutex *m, struct scm_cond *c,
|
|||
|
||||
/* We woke up for some reason. Reacquire the mutex before doing
|
||||
anything else. */
|
||||
if (scm_is_eq (m->owner, SCM_BOOL_F))
|
||||
{
|
||||
m->owner = current_thread->handle;
|
||||
scm_i_pthread_mutex_unlock (&m->lock);
|
||||
}
|
||||
else if (kind == SCM_MUTEX_RECURSIVE &&
|
||||
if (kind == SCM_MUTEX_RECURSIVE &&
|
||||
scm_is_eq (m->owner, current_thread->handle))
|
||||
{
|
||||
m->level++;
|
||||
|
@ -1330,6 +1325,12 @@ timed_wait (enum scm_mutex_kind kind, struct scm_mutex *m, struct scm_cond *c,
|
|||
else
|
||||
while (1)
|
||||
{
|
||||
if (scm_is_eq (m->owner, SCM_BOOL_F))
|
||||
{
|
||||
m->owner = current_thread->handle;
|
||||
scm_i_pthread_mutex_unlock (&m->lock);
|
||||
break;
|
||||
}
|
||||
block_self (m->waiting, &m->lock, waittime);
|
||||
if (scm_is_eq (m->owner, SCM_BOOL_F))
|
||||
{
|
||||
|
@ -1348,11 +1349,8 @@ timed_wait (enum scm_mutex_kind kind, struct scm_mutex *m, struct scm_cond *c,
|
|||
else if (err == ETIMEDOUT)
|
||||
return SCM_BOOL_F;
|
||||
else if (err == EINTR)
|
||||
{
|
||||
scm_async_tick ();
|
||||
scm_i_scm_pthread_mutex_lock (&m->lock);
|
||||
continue;
|
||||
}
|
||||
/* Let caller run scm_async_tick() and loop. */
|
||||
return SCM_BOOL_T;
|
||||
else
|
||||
{
|
||||
/* Shouldn't happen. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue