From 50b224dd15c5e4aab0d04c5c5ad7d224fbeb1855 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Sun, 23 Sep 2007 00:01:50 +0000 Subject: * eval.c, intern.h, ext/thread/thread.c: should not free queue while any live threads are waiting. [ruby-dev:30653] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_6@13495 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/thread/thread.c | 50 +++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) (limited to 'ext') diff --git a/ext/thread/thread.c b/ext/thread/thread.c index 3dba9ba32a..bca807725e 100644 --- a/ext/thread/thread.c +++ b/ext/thread/thread.c @@ -24,11 +24,12 @@ static VALUE rb_cSizedQueue; static VALUE set_critical(VALUE value); static VALUE -thread_exclusive_do(void) +thread_exclusive(VALUE (*func)(ANYARGS), VALUE arg) { - rb_thread_critical = 1; + VALUE critical = rb_thread_critical; - return rb_yield(Qundef); + rb_thread_critical = 1; + return rb_ensure(func, arg, set_critical, (VALUE)critical); } /* @@ -43,7 +44,7 @@ thread_exclusive_do(void) static VALUE rb_thread_exclusive(void) { - return rb_ensure(thread_exclusive_do, Qundef, set_critical, rb_thread_critical); + return thread_exclusive(rb_yield, Qundef); } typedef struct _Entry { @@ -147,7 +148,7 @@ shift_list(List *list) VALUE value; entry = list->entries; - if (!entry) return Qundef; + if (!entry) return Qnil; list->entries = entry->next; if (entry == list->last_entry) { @@ -269,20 +270,12 @@ wait_list(List *list) } static void -assert_no_survivors(List *waiting, const char *label, void *addr) +kill_waiting_threads(List *waiting) { Entry *entry; - VALUE ths = 0; for (entry = waiting->entries; entry; entry = entry->next) { - if (RTEST(wake_thread(entry->value))) { - if (!ths) ths = rb_ary_new(); - rb_ary_push(ths, entry->value); - } - } - if (ths) { - rb_bug("%s %p freed with live thread(s) %s waiting", - label, addr, RSTRING_PTR(rb_inspect(ths))); + rb_thread_kill(entry->value); } } @@ -334,7 +327,7 @@ finalize_mutex(Mutex *mutex) static void free_mutex(Mutex *mutex) { - assert_no_survivors(&mutex->waiting, "mutex", mutex); + kill_waiting_threads(&mutex->waiting); finalize_mutex(mutex); xfree(mutex); } @@ -493,10 +486,8 @@ set_critical(VALUE value) static VALUE unlock_mutex(Mutex *mutex) { - VALUE waking; + VALUE waking = thread_exclusive(unlock_mutex_inner, (VALUE)mutex); - rb_thread_critical = 1; - waking = rb_ensure(unlock_mutex_inner, (VALUE)mutex, set_critical, 0); if (!RTEST(waking)) { return Qfalse; } @@ -544,10 +535,9 @@ rb_mutex_exclusive_unlock(VALUE self) VALUE waking; Data_Get_Struct(self, Mutex, mutex); - rb_thread_critical = 1; - waking = rb_ensure(rb_mutex_exclusive_unlock_inner, (VALUE)mutex, set_critical, 0); + waking = thread_exclusive(rb_mutex_exclusive_unlock_inner, (VALUE)mutex); - if (waking == Qundef || !RTEST(waking)) { + if (!RTEST(waking)) { return Qnil; } @@ -622,7 +612,7 @@ finalize_condvar(ConditionVariable *condvar) static void free_condvar(ConditionVariable *condvar) { - assert_no_survivors(&condvar->waiting, "condition variable", condvar); + kill_waiting_threads(&condvar->waiting); finalize_condvar(condvar); xfree(condvar); } @@ -732,8 +722,7 @@ rb_condvar_broadcast(VALUE self) Data_Get_Struct(self, ConditionVariable, condvar); - rb_thread_critical = 1; - rb_ensure(wake_all, (VALUE)&condvar->waiting, set_critical, 0); + thread_exclusive(wake_all, (VALUE)&condvar->waiting); rb_thread_schedule(); return self; @@ -750,9 +739,8 @@ rb_condvar_broadcast(VALUE self) static void signal_condvar(ConditionVariable *condvar) { - VALUE waking; - rb_thread_critical = 1; - waking = rb_ensure(wake_one, (VALUE)&condvar->waiting, set_critical, 0); + VALUE waking = thread_exclusive(wake_one, (VALUE)&condvar->waiting); + if (RTEST(waking)) { run_thread(waking); } @@ -827,9 +815,9 @@ finalize_queue(Queue *queue) static void free_queue(Queue *queue) { - assert_no_survivors(&queue->mutex.waiting, "queue", queue); - assert_no_survivors(&queue->space_available.waiting, "queue", queue); - assert_no_survivors(&queue->value_available.waiting, "queue", queue); + kill_waiting_threads(&queue->mutex.waiting); + kill_waiting_threads(&queue->space_available.waiting); + kill_waiting_threads(&queue->value_available.waiting); finalize_queue(queue); xfree(queue); } -- cgit v1.2.3