* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
# Thread and Fiber
|
|
|
|
|
2007-06-27 20:26:31 +04:00
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
Thread.new{
|
|
|
|
}.join
|
|
|
|
:ok
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
Thread.new{
|
|
|
|
:ok
|
|
|
|
}.value
|
|
|
|
}
|
2013-06-23 10:41:37 +04:00
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
begin
|
2007-06-27 20:26:31 +04:00
|
|
|
v = 0
|
|
|
|
(1..200).map{|i|
|
|
|
|
Thread.new{
|
|
|
|
i
|
|
|
|
}
|
|
|
|
}.each{|t|
|
|
|
|
v += t.value
|
|
|
|
}
|
2013-06-23 10:41:37 +04:00
|
|
|
v == 20100 ? :ok : v
|
|
|
|
rescue ThreadError => e
|
2013-12-05 16:59:09 +04:00
|
|
|
:ok if /can't create Thread/ =~ e.message
|
2013-06-23 10:41:37 +04:00
|
|
|
end
|
2007-06-27 20:26:31 +04:00
|
|
|
}
|
2016-04-06 10:59:37 +03:00
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
begin
|
|
|
|
:ok if 5000 == 5000.times{|e|
|
2007-06-27 20:26:31 +04:00
|
|
|
(1..2).map{
|
|
|
|
Thread.new{
|
|
|
|
}
|
|
|
|
}.each{|e|
|
2007-12-25 07:16:06 +03:00
|
|
|
e.join()
|
|
|
|
}
|
|
|
|
}
|
2016-04-06 10:59:37 +03:00
|
|
|
rescue ThreadError => e
|
|
|
|
:ok if /can't create Thread/ =~ e.message
|
|
|
|
end
|
2007-12-25 07:16:06 +03:00
|
|
|
}
|
2016-04-06 10:59:37 +03:00
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
begin
|
|
|
|
:ok if 5000 == 5000.times{|e|
|
2007-12-25 07:16:06 +03:00
|
|
|
(1..2).map{
|
|
|
|
Thread.new{
|
|
|
|
}
|
|
|
|
}.each{|e|
|
|
|
|
e.join(1000000000)
|
2007-06-27 20:26:31 +04:00
|
|
|
}
|
|
|
|
}
|
2016-04-06 10:59:37 +03:00
|
|
|
rescue ThreadError => e
|
|
|
|
:ok if /can't create Thread/ =~ e.message
|
|
|
|
end
|
2007-06-27 20:26:31 +04:00
|
|
|
}
|
2013-06-23 10:41:37 +04:00
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
begin
|
|
|
|
:ok if 5000 == 5000.times{
|
2007-06-27 20:26:31 +04:00
|
|
|
t = Thread.new{}
|
|
|
|
while t.alive?
|
|
|
|
Thread.pass
|
|
|
|
end
|
|
|
|
}
|
2013-06-23 10:41:37 +04:00
|
|
|
rescue NoMemoryError
|
|
|
|
:ok
|
|
|
|
end
|
2007-06-27 20:26:31 +04:00
|
|
|
}
|
|
|
|
assert_equal %q{100}, %q{
|
|
|
|
100.times{
|
|
|
|
Thread.new{loop{Thread.pass}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
Thread.new{
|
|
|
|
:ok
|
|
|
|
}.join.value
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
begin
|
|
|
|
Thread.new{
|
|
|
|
raise "ok"
|
|
|
|
}.join
|
|
|
|
rescue => e
|
|
|
|
e
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
ans = nil
|
|
|
|
t = Thread.new{
|
|
|
|
begin
|
|
|
|
sleep 0.5
|
|
|
|
ensure
|
|
|
|
ans = :ok
|
|
|
|
end
|
|
|
|
}
|
2014-09-21 08:54:46 +04:00
|
|
|
Thread.pass until t.stop?
|
2007-06-27 20:26:31 +04:00
|
|
|
t.kill
|
|
|
|
t.join
|
|
|
|
ans
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
t = Thread.new{
|
|
|
|
sleep
|
|
|
|
}
|
|
|
|
sleep 0.1
|
|
|
|
t.raise
|
|
|
|
begin
|
|
|
|
t.join
|
|
|
|
:ng
|
|
|
|
rescue
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
t = Thread.new{
|
|
|
|
loop{}
|
|
|
|
}
|
|
|
|
Thread.pass
|
|
|
|
t.raise
|
|
|
|
begin
|
|
|
|
t.join
|
|
|
|
:ng
|
|
|
|
rescue
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_equal %q{ok}, %q{
|
|
|
|
t = Thread.new{
|
|
|
|
}
|
|
|
|
Thread.pass
|
|
|
|
t.join
|
|
|
|
t.raise # raise to exited thread
|
|
|
|
begin
|
|
|
|
t.join
|
|
|
|
:ok
|
|
|
|
rescue
|
|
|
|
:ng
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_equal %q{run}, %q{
|
|
|
|
t = Thread.new{
|
|
|
|
loop{}
|
|
|
|
}
|
|
|
|
st = t.status
|
|
|
|
t.kill
|
|
|
|
st
|
|
|
|
}
|
|
|
|
assert_equal %q{sleep}, %q{
|
|
|
|
t = Thread.new{
|
|
|
|
sleep
|
|
|
|
}
|
|
|
|
sleep 0.1
|
|
|
|
st = t.status
|
|
|
|
t.kill
|
|
|
|
st
|
|
|
|
}
|
|
|
|
assert_equal %q{false}, %q{
|
|
|
|
t = Thread.new{
|
|
|
|
}
|
|
|
|
t.kill
|
|
|
|
sleep 0.1
|
|
|
|
t.status
|
|
|
|
}
|
|
|
|
assert_equal %q{[ThreadGroup, true]}, %q{
|
|
|
|
ptg = Thread.current.group
|
|
|
|
Thread.new{
|
|
|
|
ctg = Thread.current.group
|
|
|
|
[ctg.class, ctg == ptg]
|
|
|
|
}.value
|
|
|
|
}
|
|
|
|
assert_equal %q{[1, 1]}, %q{
|
|
|
|
thg = ThreadGroup.new
|
|
|
|
|
|
|
|
t = Thread.new{
|
|
|
|
thg.add Thread.current
|
|
|
|
sleep
|
|
|
|
}
|
|
|
|
sleep 0.1
|
|
|
|
[thg.list.size, ThreadGroup::Default.list.size]
|
|
|
|
}
|
2008-01-18 17:49:43 +03:00
|
|
|
assert_equal %q{true}, %q{
|
|
|
|
thg = ThreadGroup.new
|
|
|
|
|
|
|
|
t = Thread.new{sleep 5}
|
|
|
|
thg.add t
|
|
|
|
thg.list.include?(t)
|
|
|
|
}
|
2007-06-27 20:26:31 +04:00
|
|
|
assert_equal %q{[true, nil, true]}, %q{
|
|
|
|
/a/ =~ 'a'
|
|
|
|
$a = $~
|
|
|
|
Thread.new{
|
|
|
|
$b = $~
|
2010-04-22 18:02:09 +04:00
|
|
|
/b/ =~ 'b'
|
2007-06-27 20:26:31 +04:00
|
|
|
$c = $~
|
2010-04-22 18:02:09 +04:00
|
|
|
}.join
|
2007-06-27 20:26:31 +04:00
|
|
|
$d = $~
|
|
|
|
[$a == $d, $b, $c != $d]
|
|
|
|
}
|
|
|
|
assert_equal %q{11}, %q{
|
|
|
|
Thread.current[:a] = 1
|
|
|
|
Thread.new{
|
|
|
|
Thread.current[:a] = 10
|
|
|
|
Thread.pass
|
|
|
|
Thread.current[:a]
|
|
|
|
}.value + Thread.current[:a]
|
|
|
|
}
|
2009-09-11 16:06:34 +04:00
|
|
|
assert_normal_exit %q{
|
2013-01-01 18:42:50 +04:00
|
|
|
begin
|
|
|
|
100.times do |i|
|
|
|
|
begin
|
|
|
|
th = Thread.start(Thread.current) {|u| u.raise }
|
|
|
|
raise
|
|
|
|
rescue
|
|
|
|
ensure
|
|
|
|
th.join
|
|
|
|
end
|
2007-08-13 00:06:59 +04:00
|
|
|
end
|
2013-01-01 18:42:50 +04:00
|
|
|
rescue
|
2007-08-13 00:06:59 +04:00
|
|
|
end
|
|
|
|
}, '[ruby-dev:31371]'
|
2008-01-25 21:02:01 +03:00
|
|
|
|
2008-01-14 13:02:51 +03:00
|
|
|
assert_equal 'true', %{
|
|
|
|
t = Thread.new { loop {} }
|
2008-01-23 05:23:21 +03:00
|
|
|
begin
|
|
|
|
pid = fork {
|
2008-01-14 13:02:51 +03:00
|
|
|
exit t.status != "run"
|
2008-01-23 05:23:21 +03:00
|
|
|
}
|
|
|
|
Process.wait pid
|
|
|
|
$?.success?
|
|
|
|
rescue NotImplementedError
|
|
|
|
true
|
|
|
|
end
|
2008-01-14 13:02:51 +03:00
|
|
|
}
|
2008-04-22 08:13:01 +04:00
|
|
|
|
2009-02-23 19:20:06 +03:00
|
|
|
assert_equal 'ok', %{
|
|
|
|
open("zzz.rb", "w") do |f|
|
|
|
|
f.puts <<-END
|
2009-02-23 19:24:46 +03:00
|
|
|
begin
|
|
|
|
Thread.new { fork { GC.start } }.join
|
|
|
|
pid, status = Process.wait2
|
|
|
|
$result = status.success? ? :ok : :ng
|
|
|
|
rescue NotImplementedError
|
2009-02-26 08:01:03 +03:00
|
|
|
$result = :ok
|
2009-02-23 19:24:46 +03:00
|
|
|
end
|
2009-02-23 19:20:06 +03:00
|
|
|
END
|
|
|
|
end
|
2009-06-22 11:28:33 +04:00
|
|
|
require "./zzz.rb"
|
2009-02-23 19:20:06 +03:00
|
|
|
$result
|
|
|
|
}
|
|
|
|
|
2008-04-22 08:13:01 +04:00
|
|
|
assert_finish 3, %{
|
2014-06-07 23:57:46 +04:00
|
|
|
th = Thread.new {sleep 0.2}
|
|
|
|
th.join(0.1)
|
2008-04-22 08:13:01 +04:00
|
|
|
th.join
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_finish 3, %{
|
|
|
|
require 'timeout'
|
2014-06-07 23:57:46 +04:00
|
|
|
th = Thread.new {sleep 0.2}
|
2008-04-22 08:13:01 +04:00
|
|
|
begin
|
2014-06-07 23:57:46 +04:00
|
|
|
Timeout.timeout(0.1) {th.join}
|
2008-04-22 08:13:01 +04:00
|
|
|
rescue Timeout::Error
|
|
|
|
end
|
|
|
|
th.join
|
|
|
|
}
|
2008-04-22 08:26:44 +04:00
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
STDERR.reopen(STDOUT)
|
|
|
|
exec "/"
|
|
|
|
}
|
2008-05-08 10:59:03 +04:00
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
(0..10).map {
|
|
|
|
Thread.new {
|
|
|
|
10000.times {
|
|
|
|
Object.new.to_s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.each {|t|
|
|
|
|
t.join
|
|
|
|
}
|
|
|
|
}
|
2008-05-19 09:20:21 +04:00
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
|
|
|
def m
|
2013-01-01 18:42:52 +04:00
|
|
|
t = Thread.new { while true; // =~ "" end }
|
2014-06-07 23:57:46 +04:00
|
|
|
sleep 0.01
|
2008-05-19 09:20:21 +04:00
|
|
|
10.times {
|
|
|
|
if /((ab)*(ab)*)*(b)/ =~ "ab"*7
|
|
|
|
return :ng if !$4
|
|
|
|
return :ng if $~.size != 5
|
|
|
|
end
|
|
|
|
}
|
|
|
|
:ok
|
|
|
|
ensure
|
|
|
|
Thread.kill t
|
|
|
|
end
|
|
|
|
m
|
|
|
|
}, '[ruby-dev:34492]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
at_exit { Fiber.new{}.resume }
|
|
|
|
}
|
|
|
|
|
* vm.c, eval_intern.h (PASS_PASSED_BLOCK):
set a VM_FRAME_FLAG_PASSED flag to skip this frame when
searching ruby-level-cfp.
* eval.c, eval_intern.h, proc.c: fix to check cfp. if there is
no valid ruby-level-cfp, cause RuntimeError exception.
[ruby-dev:34128]
* vm_core.h, vm_evalbody.c, vm.c, vm_dump.c, vm_insnhelper.c,
insns.def: rename FRAME_MAGIC_* to VM_FRAME_MAGIC_*.
* KNOWNBUGS.rb, bootstraptest/test*.rb: move solved bugs.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-06-11 01:46:43 +04:00
|
|
|
assert_normal_exit %q{
|
|
|
|
g = enum_for(:local_variables)
|
|
|
|
loop { g.next }
|
|
|
|
}, '[ruby-dev:34128]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
g = enum_for(:block_given?)
|
|
|
|
loop { g.next }
|
|
|
|
}, '[ruby-dev:34128]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
g = enum_for(:binding)
|
|
|
|
loop { g.next }
|
|
|
|
}, '[ruby-dev:34128]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
g = "abc".enum_for(:scan, /./)
|
|
|
|
loop { g.next }
|
|
|
|
}, '[ruby-dev:34128]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
g = Module.enum_for(:new)
|
|
|
|
loop { g.next }
|
|
|
|
}, '[ruby-dev:34128]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
Fiber.new(&Object.method(:class_eval)).resume("foo")
|
|
|
|
}, '[ruby-dev:34128]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
Thread.new("foo", &Object.method(:class_eval)).join
|
|
|
|
}, '[ruby-dev:34128]'
|
2008-06-12 17:01:38 +04:00
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
|
|
|
begin
|
|
|
|
Thread.new { Thread.stop }
|
|
|
|
Thread.stop
|
|
|
|
:ng
|
|
|
|
rescue Exception
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
|
|
|
begin
|
2016-08-30 09:22:30 +03:00
|
|
|
m1, m2 = Thread::Mutex.new, Thread::Mutex.new
|
2014-06-07 23:57:46 +04:00
|
|
|
f1 = f2 = false
|
|
|
|
Thread.new { m1.lock; f2 = true; sleep 0.001 until f1; m2.lock }
|
|
|
|
m2.lock; f1 = true; sleep 0.001 until f2; m1.lock
|
2008-06-12 17:01:38 +04:00
|
|
|
:ng
|
|
|
|
rescue Exception
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2016-08-30 09:22:30 +03:00
|
|
|
m = Thread::Mutex.new
|
2014-06-07 23:57:46 +04:00
|
|
|
Thread.new { m.lock }; sleep 0.1; m.lock
|
2008-06-12 17:01:38 +04:00
|
|
|
:ok
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2016-08-30 09:22:30 +03:00
|
|
|
m = Thread::Mutex.new
|
2008-06-12 17:01:38 +04:00
|
|
|
Thread.new { m.lock }; m.lock
|
|
|
|
:ok
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2016-08-30 09:22:30 +03:00
|
|
|
m = Thread::Mutex.new
|
2008-06-12 17:01:38 +04:00
|
|
|
Thread.new { m.lock }.join; m.lock
|
|
|
|
:ok
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2016-08-30 09:22:30 +03:00
|
|
|
m = Thread::Mutex.new
|
2014-06-07 23:57:46 +04:00
|
|
|
Thread.new { m.lock; sleep 0.2 }
|
|
|
|
sleep 0.1; m.lock
|
2008-06-12 17:01:38 +04:00
|
|
|
:ok
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2016-08-30 09:22:30 +03:00
|
|
|
m = Thread::Mutex.new
|
2014-06-07 23:57:46 +04:00
|
|
|
Thread.new { m.lock; sleep 0.2; m.unlock }
|
|
|
|
sleep 0.1; m.lock
|
2008-06-12 17:01:38 +04:00
|
|
|
:ok
|
|
|
|
}
|
2008-07-10 07:10:00 +04:00
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
|
|
|
t = Thread.new {`echo`}
|
|
|
|
t.join
|
|
|
|
$? ? :ng : :ok
|
2008-07-10 18:52:24 +04:00
|
|
|
}, '[ruby-dev:35414]'
|
2008-08-31 11:39:45 +04:00
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2008-10-28 03:52:32 +03:00
|
|
|
begin
|
2012-11-26 14:14:01 +04:00
|
|
|
100.times{
|
|
|
|
(1..100).map{ Thread.new(true) {|x| x == false } }.each{|th| th.join}
|
|
|
|
}
|
2008-10-28 03:52:32 +03:00
|
|
|
rescue NoMemoryError, StandardError
|
|
|
|
end
|
|
|
|
:ok
|
2008-08-31 11:39:45 +04:00
|
|
|
}
|
2009-11-15 18:10:49 +03:00
|
|
|
|
|
|
|
assert_equal 'ok', %{
|
|
|
|
open("zzz.rb", "w") do |f|
|
2014-06-07 23:57:46 +04:00
|
|
|
f.puts <<-'end;' # do
|
2009-11-15 18:10:49 +03:00
|
|
|
begin
|
2016-08-30 09:22:30 +03:00
|
|
|
m = Thread::Mutex.new
|
2009-11-24 04:30:00 +03:00
|
|
|
parent = Thread.current
|
2014-06-07 23:57:46 +04:00
|
|
|
th1 = Thread.new { m.lock; sleep }
|
|
|
|
sleep 0.01 until th1.stop?
|
2009-11-15 18:10:49 +03:00
|
|
|
Thread.new do
|
2014-06-07 23:57:46 +04:00
|
|
|
sleep 0.01 until parent.stop?
|
2009-11-24 04:30:00 +03:00
|
|
|
begin
|
|
|
|
fork { GC.start }
|
|
|
|
rescue Exception
|
|
|
|
parent.raise $!
|
|
|
|
end
|
2014-06-07 23:57:46 +04:00
|
|
|
th1.run
|
2009-11-15 18:10:49 +03:00
|
|
|
end
|
|
|
|
m.lock
|
|
|
|
pid, status = Process.wait2
|
|
|
|
$result = status.success? ? :ok : :ng
|
|
|
|
rescue NotImplementedError
|
|
|
|
$result = :ok
|
|
|
|
end
|
2014-06-07 23:57:46 +04:00
|
|
|
end;
|
2009-11-15 18:10:49 +03:00
|
|
|
end
|
|
|
|
require "./zzz.rb"
|
|
|
|
$result
|
|
|
|
}
|
2009-11-18 12:25:11 +03:00
|
|
|
|
|
|
|
assert_finish 3, %q{
|
|
|
|
require 'thread'
|
|
|
|
|
2016-08-30 09:22:30 +03:00
|
|
|
lock = Thread::Mutex.new
|
|
|
|
cond = Thread::ConditionVariable.new
|
2009-11-18 12:25:11 +03:00
|
|
|
t = Thread.new do
|
|
|
|
lock.synchronize do
|
|
|
|
cond.wait(lock)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-11-19 03:56:44 +03:00
|
|
|
begin
|
|
|
|
pid = fork do
|
|
|
|
# Child
|
|
|
|
STDOUT.write "This is the child process.\n"
|
|
|
|
STDOUT.write "Child process exiting.\n"
|
|
|
|
end
|
|
|
|
Process.waitpid(pid)
|
|
|
|
rescue NotImplementedError
|
2009-11-18 12:25:11 +03:00
|
|
|
end
|
2009-12-10 09:49:15 +03:00
|
|
|
}, '[ruby-core:23572]'
|
|
|
|
|
|
|
|
assert_equal 'ok', %q{
|
2009-12-11 10:47:29 +03:00
|
|
|
begin
|
2014-06-07 23:57:46 +04:00
|
|
|
Process.waitpid2(fork {})[1].success? ? 'ok' : 'ng'
|
2009-12-11 10:47:29 +03:00
|
|
|
rescue NotImplementedError
|
|
|
|
'ok'
|
|
|
|
end
|
2009-12-10 09:49:15 +03:00
|
|
|
}
|
2010-04-27 18:06:16 +04:00
|
|
|
|
|
|
|
assert_equal 'foo', %q{
|
2014-06-07 23:57:46 +04:00
|
|
|
i = 0
|
|
|
|
Thread.start {sleep 1; exit!}
|
|
|
|
f = proc {|s, c| /#{c.call; s}/o }
|
|
|
|
th2 = Thread.new {
|
|
|
|
sleep 0.01 until i == 1
|
|
|
|
i = 2
|
|
|
|
f.call("bar", proc {sleep 2});
|
|
|
|
nil
|
|
|
|
}
|
|
|
|
th1 = Thread.new {
|
|
|
|
f.call("foo", proc {i = 1; sleep 0.01 until i == 2; sleep 0.01})
|
|
|
|
nil
|
|
|
|
}
|
|
|
|
[th1, th2].each {|t| t.join }
|
2010-04-27 18:06:16 +04:00
|
|
|
GC.start
|
|
|
|
f.call.source
|
|
|
|
}
|