3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 18:31:49 +00:00

Fix implementation of scoped_timer under Linux where it was

incorrectly assumed that `pthread_cond_timedwait()` would exit
due to a condition variable being signaled or a timeout occuring.

According to the documentation `pthread_cond_timedwait()` might
spuriously wake so we introduce a new variable `m_signal_sent` (that is
guarded by an existing mutex) that is used as the variable to check that
the thread wake was not spurious.

This is intended to partially fix #839 .
This commit is contained in:
Dan Liew 2016-12-11 23:07:48 +00:00
parent 2307a7ffa7
commit bd1f07f864

View file

@ -73,6 +73,7 @@ struct scoped_timer::imp {
pthread_cond_t m_cond;
unsigned m_ms;
bool m_initialized;
bool m_signal_sent;
#else
// Other
#endif
@ -119,10 +120,18 @@ struct scoped_timer::imp {
pthread_mutex_lock(&st->m_mutex);
st->m_initialized = true;
int e = pthread_cond_timedwait(&st->m_cond, &st->m_mutex, &end_time);
ENSURE(e == 0 || e == ETIMEDOUT);
int e = 0;
// `pthread_cond_timedwait()` may spuriously wake even if the signal
// was not sent so we loop until a timeout occurs or the signal was
// **really** sent.
while (!(e == 0 && st->m_signal_sent)) {
e = pthread_cond_timedwait(&st->m_cond, &st->m_mutex, &end_time);
ENSURE(e == 0 || e == ETIMEDOUT);
if (e == ETIMEDOUT)
break;
}
pthread_mutex_unlock(&st->m_mutex);
if (e == ETIMEDOUT)
st->m_eh->operator()();
return 0;
@ -170,6 +179,7 @@ struct scoped_timer::imp {
// Linux & FreeBSD
m_ms = ms;
m_initialized = false;
m_signal_sent = false;
ENSURE(pthread_mutex_init(&m_mutex, NULL) == 0);
ENSURE(pthread_cond_init(&m_cond, NULL) == 0);
ENSURE(pthread_create(&m_thread_id, NULL, &thread_func, this) == 0);
@ -218,7 +228,10 @@ struct scoped_timer::imp {
if (!init)
sched_yield();
}
pthread_mutex_lock(&m_mutex);
m_signal_sent = true;
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
pthread_join(m_thread_id, NULL);
pthread_cond_destroy(&m_cond);