Revision: 1931 http://trac.macosforge.org/projects/ruby/changeset/1931 Author: lsansonetti@apple.com Date: 2009-06-25 23:01:49 -0700 (Thu, 25 Jun 2009) Log Message: ----------- fixed the kill of a thread which is waiting for a cond var Modified Paths: -------------- MacRuby/branches/experimental/thread.c MacRuby/branches/experimental/vm.cpp MacRuby/branches/experimental/vm.h Modified: MacRuby/branches/experimental/thread.c =================================================================== --- MacRuby/branches/experimental/thread.c 2009-06-26 04:21:03 UTC (rev 1930) +++ MacRuby/branches/experimental/thread.c 2009-06-26 06:01:49 UTC (rev 1931) @@ -250,11 +250,9 @@ rb_thread_kill(VALUE thread, SEL sel) { rb_vm_thread_t *t = GetThreadPtr(thread); - if (t->status == THREAD_KILLED) { - // Already being killed! - return thread; + if (t->status != THREAD_KILLED) { + rb_vm_thread_cancel(t); } - rb_vm_thread_cancel(t); return thread; } Modified: MacRuby/branches/experimental/vm.cpp =================================================================== --- MacRuby/branches/experimental/vm.cpp 2009-06-26 04:21:03 UTC (rev 1930) +++ MacRuby/branches/experimental/vm.cpp 2009-06-26 06:01:49 UTC (rev 1931) @@ -4285,6 +4285,9 @@ static inline void rb_vm_thread_throw_kill(void) { + // Killing a thread is implemented using a non-catchable (from Ruby) + // exception, which allows us to call the ensure blocks before dying, + // which is unfortunately covered in the Ruby specifications. rb_vm_rethrow(); } @@ -4378,24 +4381,41 @@ t->vm = vm; t->value = Qundef; t->status = THREAD_ALIVE; + t->in_cond_wait = false; assert(pthread_mutex_init(&t->sleep_mutex, NULL) == 0); assert(pthread_cond_init(&t->sleep_cond, NULL) == 0); } +static inline void +pre_wait(rb_vm_thread_t *t) +{ + t->status = THREAD_SLEEP; + assert(pthread_mutex_lock(&t->sleep_mutex) == 0); + t->in_cond_wait = true; +} + +static inline void +post_wait(rb_vm_thread_t *t) +{ + t->in_cond_wait = false; + assert(pthread_mutex_unlock(&t->sleep_mutex) == 0); + if (t->status == THREAD_KILLED) { + rb_vm_thread_throw_kill(); + } + t->status = THREAD_ALIVE; +} + extern "C" void rb_thread_sleep_forever() { rb_vm_thread_t *t = GET_THREAD(); - t->status = THREAD_SLEEP; - assert(pthread_mutex_lock(&t->sleep_mutex) == 0); + pre_wait(t); const int code = pthread_cond_wait(&t->sleep_cond, &t->sleep_mutex); assert(code == 0 || code == ETIMEDOUT); - assert(pthread_mutex_unlock(&t->sleep_mutex) == 0); - - t->status = THREAD_ALIVE; + post_wait(t); } extern "C" @@ -4414,15 +4434,11 @@ } rb_vm_thread_t *t = GET_THREAD(); - t->status = THREAD_SLEEP; - - assert(pthread_mutex_lock(&t->sleep_mutex) == 0); + pre_wait(t); const int code = pthread_cond_timedwait(&t->sleep_cond, &t->sleep_mutex, &ts); assert(code == 0 || code == ETIMEDOUT); - assert(pthread_mutex_unlock(&t->sleep_mutex) == 0); - - t->status = THREAD_ALIVE; + post_wait(t); } extern "C" @@ -4446,7 +4462,18 @@ rb_vm_thread_throw_kill(); } else { - assert(pthread_cancel(t->thread) == 0); + if (t->in_cond_wait) { + // We are trying to kill a thread which is currently waiting + // for a condition variable (#sleep). Instead of canceling the + // thread, we are simply signaling the variable, and the thread + // will autodestroy itself, to work around a stack unwinding bug + // in the Mac OS X pthread implementation that messes our C++ + // exception handlers. + assert(pthread_cond_signal(&t->sleep_cond) == 0); + } + else { + assert(pthread_cancel(t->thread) == 0); + } } } Modified: MacRuby/branches/experimental/vm.h =================================================================== --- MacRuby/branches/experimental/vm.h 2009-06-26 04:21:03 UTC (rev 1930) +++ MacRuby/branches/experimental/vm.h 2009-06-26 06:01:49 UTC (rev 1931) @@ -90,6 +90,7 @@ pthread_mutex_t sleep_mutex; pthread_cond_t sleep_cond; rb_vm_thread_status_t status; + bool in_cond_wait; } rb_vm_thread_t; typedef struct rb_vm_outer {
participants (1)
-
source_changes@macosforge.org