Wait on sema_b again to ensure pthread_cond_wait() functions atomically as required by POSIX.

Since holding sema_b before aquiring waiters_count_lock_ can lead to deadlocks try to aquire waiters_count_lock_ opportunistically. If it fails then release sema_b and sched_yield() to give the other thread (which has aquired waiters_count_lock_ and is now waiting on sema_b) a chance to aquire sema_b before we retry the whole procedure.

Signed-off-by: Liu Hao <lh_mouse@126.com>
This commit is contained in:
xnor 2019-08-12 17:27:17 +00:00 committed by Liu Hao
parent 1ebdd63cff
commit 330025c54b

View File

@ -431,10 +431,20 @@ pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *external_mutex)
} else if (_c->valid != (unsigned int)LIFE_COND)
return EINVAL;
tryagain:
r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
if (r != 0)
return r;
EnterCriticalSection (&_c->waiters_count_lock_);
if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
{
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
if (r != 0)
return r;
sched_yield();
goto tryagain;
}
_c->waiters_count_++;
LeaveCriticalSection(&_c->waiters_count_lock_);
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
@ -485,10 +495,20 @@ pthread_cond_timedwait_impl (pthread_cond_t *c, pthread_mutex_t *external_mutex,
dwr = dwMilliSecs(_pthread_time_in_ms_from_timespec(t));
}
tryagain:
r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
if (r != 0)
return r;
EnterCriticalSection (&_c->waiters_count_lock_);
if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
{
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
if (r != 0)
return r;
sched_yield();
goto tryagain;
}
_c->waiters_count_++;
LeaveCriticalSection(&_c->waiters_count_lock_);
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);