From 1e12ead7197debcbaaea3fe89f8ed304e1b2c388 Mon Sep 17 00:00:00 2001 From: Juan Jose Garcia Ripoll Date: Tue, 22 Sep 2009 22:32:09 +0200 Subject: [PATCH] The routines that wait on condition variables should verify that the calling thread owns the lock and then mark it as released, at least for the duration of pthread_count_timedwait(). --- src/c/threads.d | 57 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/src/c/threads.d b/src/c/threads.d index 59a8fc4ed..cac7cddc0 100644 --- a/src/c/threads.d +++ b/src/c/threads.d @@ -697,13 +697,33 @@ mp_condition_variable_wait(cl_object cv, cl_object lock) #ifdef ECL_WINDOWS_THREADS FEerror("Condition variables are not supported under Windows.", 0); #else + int count, rc; + cl_object own_process = mp_current_process(); if (type_of(cv) != t_condition_variable) FEwrong_type_argument(@'mp::condition-variable', cv); if (type_of(lock) != t_lock) FEwrong_type_argument(@'mp::lock', lock); - if (pthread_cond_wait(&cv->condition_variable.cv, - &lock->lock.mutex) == 0) - lock->lock.holder = mp_current_process(); + if (lock->lock.holder != own_process) { + FEerror("Attempt to wait on a condition variable using lock~%~S" + "~%which is not owned by process~%~S", 2, lock, own_process); + } + if (lock->lock.counter > 0) { + FEerror("mp:condition-variable-wait can not be used with recursive" + " locks:~%~S", 1, lock); + } + /* Note: this is highly unsafe. We are marking the lock as released + * without knowing whether pthread_cond_wait worked as expected. */ + lock->lock.counter = 0; + lock->lock.holder = Cnil; + rc = pthread_cond_wait(&cv->condition_variable.cv, + &lock->lock.mutex); + lock->lock.holder = own_process; + lock->lock.counter = 1; + if (rc != 0) { + FEerror("System returned error code ~D " + "when waiting on condition variable~%~A~%and lock~%~A.", + 3, MAKE_FIXNUM(rc), cv, lock); + } #endif @(return Ct) } @@ -714,6 +734,8 @@ mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) #ifdef ECL_WINDOWS_THREADS FEerror("Condition variables are not supported under Windows.", 0); #else + int rc; + cl_object own_process = mp_current_process(); double r; struct timespec ts; struct timeval tp; @@ -722,6 +744,14 @@ mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) FEwrong_type_argument(@'mp::condition-variable', cv); if (type_of(lock) != t_lock) FEwrong_type_argument(@'mp::lock', lock); + if (lock->lock.holder != own_process) { + FEerror("Attempt to wait on a condition variable using lock~%~S" + "~%which is not owned by process~%~S", 2, lock, own_process); + } + if (lock->lock.counter > 0) { + FEerror("mp:condition-variable-wait can not be used with recursive" + " locks:~%~S", 1, lock); + } /* INV: ecl_minusp() makes sure `seconds' is real */ if (ecl_minusp(seconds)) cl_error(9, @'simple-type-error', @':format-control', @@ -741,13 +771,20 @@ mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) ts.tv_nsec -= 1e9; ts.tv_sec++; } - if (pthread_cond_timedwait(&cv->condition_variable.cv, - &lock->lock.mutex, &ts) == 0) { - lock->lock.holder = mp_current_process(); - @(return Ct) - } else { - @(return Cnil) - } + /* Note: this is highly unsafe. We are marking the lock as released + * without knowing whether pthread_cond_wait worked as expected. */ + lock->lock.counter = 0; + lock->lock.holder = Cnil; + rc = pthread_cond_timedwait(&cv->condition_variable.cv, + &lock->lock.mutex, &ts); + lock->lock.holder = own_process; + lock->lock.counter = 1; + if (rc != ETIMEDOUT) { + FEerror("System returned error code ~D " + "when waiting on condition variable~%~A~%and lock~%~A.", + 3, MAKE_FIXNUM(rc), cv, lock); + } + @(return (rc? Ct : Cnil)) #endif }