1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
nobu 2008-04-22 04:13:01 +00:00
parent 62aa7aae51
commit 9c77076296
3 changed files with 77 additions and 10 deletions

View file

@ -1,3 +1,8 @@
Tue Apr 22 13:12:58 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* 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@ruby-lang.org>
* vm_insnhelper.c (vm_get_ev_const): search from the base klass if it

View file

@ -213,3 +213,19 @@ assert_equal 'true', %{
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
}

View file

@ -461,20 +461,42 @@ rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
/* +infty, for this purpose */
#define DELAY_INFTY 1E30
static VALUE
thread_join(rb_thread_t *target_th, double delay)
{
rb_thread_t *th = GET_THREAD();
double now, limit = timeofday() + delay;
struct join_arg {
rb_thread_t *target, *waiting;
double limit;
int forever;
};
thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
static VALUE
remove_from_join_list(VALUE arg)
{
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);