From 9c7707629608304a2eaf674a72af16c95ebc4f52 Mon Sep 17 00:00:00 2001 From: nobu Date: Tue, 22 Apr 2008 04:13:01 +0000 Subject: * thread.c (thread_join): remove the current thread from the join list of the target thread. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16135 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- thread.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 9 deletions(-) (limited to 'thread.c') diff --git a/thread.c b/thread.c index d2c9adc306..bcabb59ec1 100644 --- a/thread.c +++ b/thread.c @@ -461,20 +461,42 @@ rb_thread_create(VALUE (*fn)(ANYARGS), void *arg) /* +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; - - thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id); + struct join_arg *p = (struct join_arg *)arg; + rb_thread_t *target_th = p->target, *th = p->waiting; if (target_th->status != THREAD_KILLED) { - th->join_list_next = target_th->join_list_head; - target_th->join_list_head = th; + rb_thread_t **pth = &target_th->join_list_head; + + 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,13 +504,37 @@ thread_join(rb_thread_t *target_th, double delay) 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); -- cgit v1.2.3