なかだです。

# 時期的に微妙ですが。

ThreadGroupの使い途があまりないなと思っていたんですが、thgroup
が追加されたのを機会に、ThreadGroup#waitというのを作ってみまし
た。


Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.491 diff -u -2 -p -r1.491 eval.c --- eval.c 22 Jul 2003 08:42:44 -0000 1.491 +++ eval.c 23 Jul 2003 07:01:00 -0000 @@ -8335,12 +8442,17 @@ rb_thread_ready(th) } +static void thgroup_notify _((VALUE, rb_thread_t)); + static void rb_thread_die(th) rb_thread_t th; { + VALUE thg = th->thgroup; + th->thgroup = 0; th->status = THREAD_KILLED; if (th->stk_ptr) free(th->stk_ptr); th->stk_ptr = 0; + thgroup_notify(thg, th); } @@ -8352,7 +8464,7 @@ rb_thread_remove(th) rb_thread_ready(th); - rb_thread_die(th); th->prev->next = th->next; th->next->prev = th->prev; + rb_thread_die(th); } @@ -9025,5 +9137,4 @@ rb_thread_kill(thread) rb_thread_ready(th); - th->thgroup = 0; th->status = THREAD_TO_KILL; if (!rb_thread_critical) rb_thread_schedule(); @@ -9180,4 +9291,18 @@ rb_thread_abort_exc_set(thread, val) } +VALUE +rb_thread_group(thread) + VALUE thread; +{ + rb_thread_t th = rb_thread_check(thread); + return th->thgroup; +} + +struct thgroup { + int enclosed, count; + VALUE group; + VALUE waiting; +}; + #define THREAD_ALLOC(th) do {\ th = ALLOC(struct thread);\ @@ -9218,4 +9343,6 @@ rb_thread_abort_exc_set(thread, val) th->thgroup = thgroup_default;\ th->locals = 0;\ +\ + ((struct thgroup *)DATA_PTR(th->thgroup))->count++;\ } while (0) @@ -9334,5 +9461,7 @@ rb_thread_start_0(fn, arg, th_arg) curr_thread->next = th; th->priority = curr_thread->priority; + ((struct thgroup *)DATA_PTR(th->thgroup))->count--; th->thgroup = curr_thread->thgroup; + ((struct thgroup *)DATA_PTR(th->thgroup))->count++; } @@ -9547,5 +9676,4 @@ rb_thread_cleanup() if (th->status != THREAD_KILLED) { rb_thread_ready(th); - th->thgroup = 0; th->priority = 0; if (th != main_thread) { @@ -9882,8 +10010,10 @@ rb_cont_call(argc, argv, cont) } -struct thgroup { - int enclosed; - VALUE group; -}; +static void +thgroup_mark(ptr) + struct thgroup *ptr; +{ + rb_gc_mark(ptr->waiting); +} static VALUE thgroup_s_alloc _((VALUE)); @@ -9895,5 +10025,5 @@ thgroup_s_alloc(klass) struct thgroup *data; - group = Data_Make_Struct(klass, struct thgroup, 0, free, data); + group = Data_Make_Struct(klass, struct thgroup, thgroup_mark, free, data); data->enclosed = 0; data->group = group; @@ -9952,5 +10082,5 @@ thgroup_add(group, thread) { rb_thread_t th; - struct thgroup *data; + struct thgroup *data, *old; rb_secure(4); @@ -9972,13 +10102,83 @@ thgroup_add(group, thread) rb_raise(rb_eThreadError, "can't move from the frozen thread group"); } - Data_Get_Struct(th->thgroup, struct thgroup, data); - if (data->enclosed) { + Data_Get_Struct(th->thgroup, struct thgroup, old); + if (old->enclosed) { rb_raise(rb_eThreadError, "can't move from the enclosed thread group"); } + --old->count; + ++data->count; th->thgroup = group; return group; } +static VALUE +thgroup_wait(group) + VALUE group; +{ + struct thgroup *data; + rb_thread_t th; + VALUE waiting, result; + + Data_Get_Struct(group, struct thgroup, data); + switch (data->count) { + case 1: + if (curr_thread->thgroup != group) break; + case 0: + return Qnil; + } + if (!(waiting = data->waiting)) { + waiting = rb_ary_new(); + OBJ_TAINT(waiting); + data->waiting = waiting; + } + rb_ary_push(waiting, curr_thread->thread); + curr_thread->status = THREAD_STOPPED; + curr_thread->wait_for = 0; + curr_thread->join = 0; + rb_thread_schedule(); + th = curr_thread->join; + curr_thread->join = 0; + result = th ? th->thread : Qnil; + if (rb_block_given_p()) { + result = rb_yield(result); + } + return result; +} + +static void +thgroup_notify(group, thread) + VALUE group; + rb_thread_t thread; +{ + struct thgroup *data; + rb_thread_t th; + VALUE waiting; + int i; + + Data_Get_Struct(group, struct thgroup, data); + --data->count; + waiting = data->waiting; + if (!waiting || !RARRAY(waiting)->len) return; + for (i = 0; i < RARRAY(waiting)->len; ++i) { + th = (rb_thread_t)RDATA(RARRAY(waiting)->ptr[i])->data; + if (!rb_thread_dead(th)) { + rb_thread_ready(th); + th->join = thread; + } + } + rb_ary_clear(waiting); +} + +static VALUE +thgroup_count(group) + VALUE group; +{ + struct thgroup *data; + + Data_Get_Struct(group, struct thgroup, data); + return INT2FIX(data->count); +} + void Init_Thread() @@ -10027,4 +10227,5 @@ Init_Thread() rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1); rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0); + rb_define_method(rb_cThread, "group", rb_thread_group, 0); rb_define_method(rb_cThread, "[]", rb_thread_aref, 1); @@ -10047,4 +10248,6 @@ Init_Thread() rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0); rb_define_method(cThGroup, "add", thgroup_add, 1); + rb_define_method(cThGroup, "wait", thgroup_wait, 0); + rb_define_method(cThGroup, "count", thgroup_count, 0); thgroup_default = rb_obj_alloc(cThGroup); rb_define_const(cThGroup, "Default", thgroup_default);
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦