ruby-changes:4641
From: ko1@a...
Date: Tue, 22 Apr 2008 13:13:24 +0900 (JST)
Subject: [ruby-changes:4641] nobu - Ruby:r16135 (trunk): * thread.c (thread_join): remove the current thread from the join list
nobu 2008-04-22 13:13:01 +0900 (Tue, 22 Apr 2008) New Revision: 16135 Modified files: trunk/ChangeLog trunk/bootstraptest/test_thread.rb trunk/thread.c Log: * thread.c (thread_join): remove the current thread from the join list of the target thread. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=16135&r2=16134&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/thread.c?r1=16135&r2=16134&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/bootstraptest/test_thread.rb?r1=16135&r2=16134&diff_format=u Index: ChangeLog =================================================================== --- ChangeLog (revision 16134) +++ ChangeLog (revision 16135) @@ -1,3 +1,8 @@ +Tue Apr 22 13:12:58 2008 Nobuyoshi Nakada <nobu@r...> + + * thread.c (thread_join): remove the current thread from the join list + of the target thread. + Tue Apr 22 12:03:50 2008 Nobuyoshi Nakada <nobu@r...> * vm_insnhelper.c (vm_get_ev_const): search from the base klass if it Index: bootstraptest/test_thread.rb =================================================================== --- bootstraptest/test_thread.rb (revision 16134) +++ bootstraptest/test_thread.rb (revision 16135) @@ -213,3 +213,19 @@ true end } + +assert_finish 3, %{ + th = Thread.new {sleep 2} + th.join(1) + th.join +} + +assert_finish 3, %{ + require 'timeout' + th = Thread.new {sleep 2} + begin + Timeout.timeout(1) {th.join} + rescue Timeout::Error + end + th.join +} Index: thread.c =================================================================== --- thread.c (revision 16134) +++ thread.c (revision 16135) @@ -461,20 +461,42 @@ /* +infty, for this purpose */ #define DELAY_INFTY 1E30 +struct join_arg { + rb_thread_t *target, *waiting; + double limit; + int forever; +}; + static VALUE -thread_join(rb_thread_t *target_th, double delay) +remove_from_join_list(VALUE arg) { - rb_thread_t *th = GET_THREAD(); - double now, limit = timeofday() + delay; + struct join_arg *p = (struct join_arg *)arg; + rb_thread_t *target_th = p->target, *th = p->waiting; - thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id); + if (target_th->status != THREAD_KILLED) { + rb_thread_t **pth = &target_th->join_list_head; - if (target_th->status != THREAD_KILLED) { - th->join_list_next = target_th->join_list_head; - target_th->join_list_head = th; + while (*pth) { + if (*pth == th) { + *pth = th->join_list_next; + break; + } + pth = &(*pth)->join_list_next; + } } + + return Qnil; +} + +static VALUE +thread_join_sleep(VALUE arg) +{ + struct join_arg *p = (struct join_arg *)arg; + rb_thread_t *target_th = p->target, *th = p->waiting; + double now, limit = p->limit; + while (target_th->status != THREAD_KILLED) { - if (delay == DELAY_INFTY) { + if (p->forever) { sleep_forever(th); } else { @@ -482,14 +504,38 @@ if (now > limit) { thread_debug("thread_join: timeout (thid: %p)\n", (void *)target_th->thread_id); - return Qnil; + return Qfalse; } sleep_wait_for_interrupt(th, limit - now); } thread_debug("thread_join: interrupted (thid: %p)\n", (void *)target_th->thread_id); } + return Qtrue; +} +static VALUE +thread_join(rb_thread_t *target_th, double delay) +{ + rb_thread_t *th = GET_THREAD(); + struct join_arg arg; + + arg.target = target_th; + arg.waiting = th; + arg.limit = timeofday() + delay; + arg.forever = delay == DELAY_INFTY; + + thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id); + + if (target_th->status != THREAD_KILLED) { + th->join_list_next = target_th->join_list_head; + target_th->join_list_head = th; + if (!rb_ensure(thread_join_sleep, (VALUE)&arg, + remove_from_join_list, (VALUE)&arg)) { + return Qnil; + } + } + thread_debug("thread_join: success (thid: %p)\n", (void *)target_th->thread_id); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/