diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index f7b33c3..2579fdf 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -708,4 +708,18 @@ class TestThreadGroup < Test::Unit::TestCase
end
assert_in_delta(t1 - t0, 1, 1)
end
+
+ def test_join
+ thgrp = ThreadGroup.new
+
+ thgrp.add(t = Thread.new{ sleep })
+
+ t0 = Time.now.to_f
+ assert_nil(thgrp.join(1))
+ t1 = Time.now.to_f
+ assert_in_delta(t1 - t0, 1, 1)
+
+ ensure
+ t.kill if t
+ end
end
diff --git a/thread.c b/thread.c
index 55ba49d..05a4f19 100644
--- a/thread.c
+++ b/thread.c
@@ -3139,6 +3139,61 @@ thgroup_list(VALUE group)
return ary;
}
+struct thgroup_join_params {
+ double limit;
+ VALUE group;
+};
+
+static int
+thgroup_join_i(st_data_t key, st_data_t value, st_data_t data)
+{
+ VALUE thread = (VALUE)key;
+ rb_thread_t *th;
+ struct thgroup_join_params *args = (struct thgroup_join_params *)data;
+ double delay = args->limit;
+
+ GetThreadPtr(thread, th);
+ if (th->thgroup == args->group) {
+ if (delay != DELAY_INFTY) delay -= timeofday();
+ if (NIL_P(thread_join(th, delay))) {
+ args->group = Qnil;
+ return ST_STOP;
+ }
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * thgrp.join -> thgrp
+ * thgrp.join(limit) -> thgrp or nil
+ *
+ * The calling thread will suspend execution until threads in the receiving
+ * ThreadGroup
exit or until limit seconds have passed.
+ * If the time limit expires, nil
will be returned, otherwise
+ * thgrp is returned.
+ *
+ */
+
+static VALUE
+thgroup_join(int argc, VALUE *argv, VALUE self)
+{
+ VALUE limit;
+ struct thgroup_join_params param;
+
+ rb_scan_args(argc, argv, "01", &limit);
+
+ if (!NIL_P(limit)) {
+ param.limit = timeofday() + rb_num2dbl(limit);
+ } else {
+ param.limit = DELAY_INFTY;
+ }
+
+ param.group = self;
+
+ st_foreach(GET_THREAD()->vm->living_threads, thgroup_join_i, (st_data_t) & param);
+ return param.group;
+}
/*
* call-seq:
@@ -4622,6 +4677,7 @@ Init_Thread(void)
rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
rb_define_method(cThGroup, "add", thgroup_add, 1);
+ rb_define_method(cThGroup, "join", thgroup_join, -1);
{
th->thgroup = th->vm->thgroup_default = rb_obj_alloc(cThGroup);