1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/bootstraptest/test_thread.rb
Koichi Sasada fd0222caed should check pending interrupts correctly.
rb_uninterruptible() disables any interrupts using handle_interrupt
feature (This function is used by `p`).
After this function, pending interrupts should be checked correctly,
however there is no chance to setup interrupt flag of working
threads, it means that nobody checks pending interrupts.
For example, it ignores terminate signal delivered at the end
of main thread and program can't stop.

This patch set interrupt flag if there are pending interrupts.
2020-04-09 12:51:51 +09:00

500 lines
7.9 KiB
Ruby

show_limit %q{
threads = []
begin
threads << Thread.new{sleep}
raise Exception, "skipping" if threads.count >= 10_000
rescue Exception => error
puts "Thread count: #{threads.count} (#{error})"
break
end while true
} if false # disable to pass CI
assert_equal %q{ok}, %q{
Thread.new{
}.join
:ok
}
assert_equal %q{ok}, %q{
Thread.new{
:ok
}.value
}
assert_equal %q{ok}, %q{
begin
v = 0
(1..200).map{|i|
Thread.new{
i
}
}.each{|t|
v += t.value
}
v == 20100 ? :ok : v
rescue ThreadError => e
:ok if /can't create Thread/ =~ e.message
end
}
assert_equal %q{ok}, %q{
begin
:ok if 5000 == 5000.times{|e|
(1..2).map{
Thread.new{
}
}.each{|e|
e.join()
}
}
rescue ThreadError => e
/can't create Thread/ =~ e.message ? :ok : e.message
end
}
assert_equal %q{ok}, %q{
begin
:ok if 5000 == 5000.times{|e|
(1..2).map{
Thread.new{
}
}.each{|e|
e.join(1000000000)
}
}
rescue ThreadError => e
/can't create Thread/ =~ e.message ? :ok : e.message
end
}
assert_equal %q{ok}, %q{
begin
:ok if 5000 == 5000.times{
t = Thread.new{}
while t.alive?
Thread.pass
end
}
rescue NoMemoryError
:ok
end
}
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
}
Thread.pass until t.stop?
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]
}
assert_equal %q{true}, %q{
thg = ThreadGroup.new
t = Thread.new{sleep 5}
thg.add t
thg.list.include?(t)
}
assert_equal %q{[true, nil, true]}, %q{
/a/ =~ 'a'
$a = $~
Thread.new{
$b = $~
/b/ =~ 'b'
$c = $~
}.join
$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]
}
assert_normal_exit %q{
begin
100.times do |i|
begin
th = Thread.start(Thread.current) {|u| u.raise }
raise
rescue
ensure
th.join
end
end
rescue
end
}, '[ruby-dev:31371]'
assert_equal 'true', %{
t = Thread.new { loop {} }
begin
pid = fork {
exit t.status != "run"
}
Process.wait pid
$?.success?
rescue NotImplementedError
true
end
}
assert_equal 'ok', %{
open("zzz.rb", "w") do |f|
f.puts <<-END
begin
Thread.new { fork { GC.start } }.join
pid, status = Process.wait2
$result = status.success? ? :ok : :ng
rescue NotImplementedError
$result = :ok
end
END
end
require "./zzz.rb"
$result
}
assert_finish 3, %{
th = Thread.new {sleep 0.2}
th.join(0.1)
th.join
}
assert_finish 3, %{
require 'timeout'
th = Thread.new {sleep 0.2}
begin
Timeout.timeout(0.1) {th.join}
rescue Timeout::Error
end
th.join
}
assert_normal_exit %q{
STDERR.reopen(STDOUT)
exec "/"
}
assert_normal_exit %q{
(0..10).map {
Thread.new {
10000.times {
Object.new.to_s
}
}
}.each {|t|
t.join
}
}
assert_equal 'ok', %q{
def m
t = Thread.new { while true; // =~ "" end }
sleep 0.01
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{
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{
Thread.new("foo", &Object.method(:class_eval)).join
}, '[ruby-dev:34128]'
assert_equal 'ok', %q{
begin
Thread.new { Thread.stop }
Thread.stop
:ng
rescue Exception
:ok
end
}
assert_equal 'ok', %q{
begin
m1, m2 = Thread::Mutex.new, Thread::Mutex.new
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
:ng
rescue Exception
:ok
end
}
assert_equal 'ok', %q{
m = Thread::Mutex.new
Thread.new { m.lock }; sleep 0.1; m.lock
:ok
}
assert_equal 'ok', %q{
m = Thread::Mutex.new
Thread.new { m.lock }; m.lock
:ok
}
assert_equal 'ok', %q{
m = Thread::Mutex.new
Thread.new { m.lock }.join; m.lock
:ok
}
assert_equal 'ok', %q{
m = Thread::Mutex.new
Thread.new { m.lock; sleep 0.2 }
sleep 0.1; m.lock
:ok
}
assert_equal 'ok', %q{
m = Thread::Mutex.new
Thread.new { m.lock; sleep 0.2; m.unlock }
sleep 0.1; m.lock
:ok
}
assert_equal 'ok', %q{
t = Thread.new {`echo`}
t.join
$? ? :ng : :ok
}, '[ruby-dev:35414]'
assert_equal 'ok', %q{
begin
100.times{
(1..100).map{ Thread.new(true) {|x| x == false } }.each{|th| th.join}
}
rescue NoMemoryError, StandardError
end
:ok
}
assert_equal 'ok', %{
open("zzz.rb", "w") do |f|
f.puts <<-'end;' # do
begin
m = Thread::Mutex.new
parent = Thread.current
th1 = Thread.new { m.lock; sleep }
sleep 0.01 until th1.stop?
Thread.new do
sleep 0.01 until parent.stop?
begin
fork { GC.start }
rescue Exception
parent.raise $!
end
th1.run
end
m.lock
pid, status = Process.wait2
$result = status.success? ? :ok : :ng
rescue NotImplementedError
$result = :ok
end
end;
end
require "./zzz.rb"
$result
}
assert_finish 3, %q{
require 'thread'
lock = Thread::Mutex.new
cond = Thread::ConditionVariable.new
t = Thread.new do
lock.synchronize do
cond.wait(lock)
end
end
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
end
}, '[ruby-core:23572]'
assert_equal 'ok', %q{
begin
Process.waitpid2(fork {})[1].success? ? 'ok' : 'ng'
rescue NotImplementedError
'ok'
end
}
assert_equal 'foo', %q{
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 }
GC.start
f.call.source
}
assert_normal_exit %q{
class C
def inspect
sleep 0.5
'C!!'
end
end
Thread.new{
loop{
p C.new
}
}
sleep 0.1
}, timeout: 5