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:
parent
62aa7aae51
commit
9c77076296
3 changed files with 77 additions and 10 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
66
thread.c
66
thread.c
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue