* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
require 'test/unit'
|
2007-08-24 22:03:44 -04:00
|
|
|
require 'fiber'
|
2007-08-25 16:54:50 -04:00
|
|
|
require 'continuation'
|
2010-05-09 13:32:45 -04:00
|
|
|
require_relative './envutil'
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
|
|
|
|
class TestFiber < Test::Unit::TestCase
|
|
|
|
def test_normal
|
|
|
|
f = Fiber.current
|
|
|
|
assert_equal(:ok2,
|
2007-06-02 03:48:29 -04:00
|
|
|
Fiber.new{|e|
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
assert_equal(:ok1, e)
|
2007-06-02 03:48:29 -04:00
|
|
|
Fiber.yield :ok2
|
2007-08-21 14:51:39 -04:00
|
|
|
}.resume(:ok1)
|
2007-06-02 03:48:29 -04:00
|
|
|
)
|
2007-08-21 14:51:39 -04:00
|
|
|
assert_equal([:a, :b], Fiber.new{|a, b| [a, b]}.resume(:a, :b))
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
end
|
|
|
|
|
2008-11-30 22:00:48 -05:00
|
|
|
def test_argument
|
|
|
|
assert_equal(4, Fiber.new {|i=4| i}.resume)
|
|
|
|
end
|
|
|
|
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
def test_term
|
2007-08-21 14:51:39 -04:00
|
|
|
assert_equal(:ok, Fiber.new{:ok}.resume)
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
assert_equal([:a, :b, :c, :d, :e],
|
|
|
|
Fiber.new{
|
|
|
|
Fiber.new{
|
|
|
|
Fiber.new{
|
|
|
|
Fiber.new{
|
|
|
|
[:a]
|
2007-08-21 14:51:39 -04:00
|
|
|
}.resume + [:b]
|
|
|
|
}.resume + [:c]
|
|
|
|
}.resume + [:d]
|
|
|
|
}.resume + [:e])
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_many_fibers
|
|
|
|
max = 10000
|
|
|
|
assert_equal(max, max.times{
|
|
|
|
Fiber.new{}
|
|
|
|
})
|
|
|
|
assert_equal(max,
|
|
|
|
max.times{|i|
|
|
|
|
Fiber.new{
|
2007-08-21 14:51:39 -04:00
|
|
|
}.resume
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2007-06-06 14:19:42 -04:00
|
|
|
def test_many_fibers_with_threads
|
|
|
|
max = 1000
|
|
|
|
@cnt = 0
|
|
|
|
(1..100).map{|ti|
|
|
|
|
Thread.new{
|
|
|
|
max.times{|i|
|
|
|
|
Fiber.new{
|
|
|
|
@cnt += 1
|
2007-08-21 14:51:39 -04:00
|
|
|
}.resume
|
2007-06-06 14:19:42 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}.each{|t|
|
|
|
|
t.join
|
|
|
|
}
|
|
|
|
assert_equal(:ok, :ok)
|
|
|
|
end
|
|
|
|
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
def test_error
|
|
|
|
assert_raise(ArgumentError){
|
|
|
|
Fiber.new # Fiber without block
|
|
|
|
}
|
2007-06-02 03:48:29 -04:00
|
|
|
assert_raise(FiberError){
|
|
|
|
f = Fiber.new{}
|
2007-08-21 14:51:39 -04:00
|
|
|
Thread.new{f.resume}.join # Fiber yielding across thread
|
2007-06-02 03:48:29 -04:00
|
|
|
}
|
|
|
|
assert_raise(FiberError){
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
f = Fiber.new{}
|
2007-08-21 14:51:39 -04:00
|
|
|
f.resume
|
|
|
|
f.resume
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
}
|
2007-06-14 23:20:13 -04:00
|
|
|
assert_raise(RuntimeError){
|
|
|
|
f = Fiber.new{
|
|
|
|
@c = callcc{|c| @c = c}
|
2007-08-21 14:51:39 -04:00
|
|
|
}.resume
|
2007-06-14 23:20:13 -04:00
|
|
|
@c.call # cross fiber callcc
|
|
|
|
}
|
2007-08-21 14:51:39 -04:00
|
|
|
assert_raise(RuntimeError){
|
|
|
|
Fiber.new{
|
|
|
|
raise
|
|
|
|
}.resume
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
}
|
2007-08-21 14:51:39 -04:00
|
|
|
assert_raise(FiberError){
|
|
|
|
Fiber.yield
|
|
|
|
}
|
|
|
|
assert_raise(FiberError){
|
|
|
|
fib = Fiber.new{
|
|
|
|
fib.resume
|
|
|
|
}
|
|
|
|
fib.resume
|
|
|
|
}
|
|
|
|
assert_raise(FiberError){
|
|
|
|
fib = Fiber.new{
|
|
|
|
Fiber.new{
|
|
|
|
fib.resume
|
|
|
|
}.resume
|
|
|
|
}
|
|
|
|
fib.resume
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
}
|
|
|
|
end
|
2007-06-05 13:55:07 -04:00
|
|
|
|
|
|
|
def test_return
|
|
|
|
assert_raise(LocalJumpError){
|
|
|
|
Fiber.new do
|
|
|
|
return
|
2007-08-21 14:51:39 -04:00
|
|
|
end.resume
|
2007-06-05 13:55:07 -04:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_throw
|
2007-09-07 14:00:44 -04:00
|
|
|
assert_raise(ArgumentError){
|
2007-06-05 13:55:07 -04:00
|
|
|
Fiber.new do
|
|
|
|
throw :a
|
2007-08-21 14:51:39 -04:00
|
|
|
end.resume
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_transfer
|
|
|
|
ary = []
|
|
|
|
f2 = nil
|
2007-08-24 22:03:44 -04:00
|
|
|
f1 = Fiber.new{
|
2007-08-21 14:51:39 -04:00
|
|
|
ary << f2.transfer(:foo)
|
|
|
|
:ok
|
|
|
|
}
|
2007-08-24 22:03:44 -04:00
|
|
|
f2 = Fiber.new{
|
2007-08-21 14:51:39 -04:00
|
|
|
ary << f1.transfer(:baz)
|
|
|
|
:ng
|
2007-06-05 13:55:07 -04:00
|
|
|
}
|
2007-08-21 14:51:39 -04:00
|
|
|
assert_equal(:ok, f1.transfer)
|
|
|
|
assert_equal([:baz], ary)
|
2007-06-05 13:55:07 -04:00
|
|
|
end
|
2007-09-28 15:04:45 -04:00
|
|
|
|
|
|
|
def test_tls
|
2009-03-05 22:56:38 -05:00
|
|
|
#
|
2007-09-28 15:04:45 -04:00
|
|
|
def tvar(var, val)
|
|
|
|
old = Thread.current[var]
|
|
|
|
begin
|
|
|
|
Thread.current[var] = val
|
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
Thread.current[var] = old
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
fb = Fiber.new {
|
|
|
|
assert_equal(nil, Thread.current[:v]); tvar(:v, :x) {
|
|
|
|
assert_equal(:x, Thread.current[:v]); Fiber.yield
|
|
|
|
assert_equal(:x, Thread.current[:v]); }
|
|
|
|
assert_equal(nil, Thread.current[:v]); Fiber.yield
|
|
|
|
raise # unreachable
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal(nil, Thread.current[:v]); tvar(:v,1) {
|
|
|
|
assert_equal(1, Thread.current[:v]); tvar(:v,3) {
|
|
|
|
assert_equal(3, Thread.current[:v]); fb.resume
|
|
|
|
assert_equal(3, Thread.current[:v]); }
|
|
|
|
assert_equal(1, Thread.current[:v]); }
|
|
|
|
assert_equal(nil, Thread.current[:v]); fb.resume
|
|
|
|
assert_equal(nil, Thread.current[:v]);
|
|
|
|
end
|
2009-02-13 01:04:25 -05:00
|
|
|
|
|
|
|
def test_alive
|
|
|
|
fib = Fiber.new{Fiber.yield}
|
|
|
|
assert_equal(true, fib.alive?)
|
|
|
|
fib.resume
|
|
|
|
assert_equal(true, fib.alive?)
|
|
|
|
fib.resume
|
|
|
|
assert_equal(false, fib.alive?)
|
|
|
|
end
|
2009-05-31 22:21:31 -04:00
|
|
|
|
|
|
|
def test_resume_self
|
|
|
|
f = Fiber.new {f.resume}
|
|
|
|
assert_raise(FiberError, '[ruby-core:23651]') {f.transfer}
|
|
|
|
end
|
2010-05-09 13:32:45 -04:00
|
|
|
|
|
|
|
def test_fiber_transfer_segv
|
|
|
|
assert_normal_exit %q{
|
|
|
|
require 'fiber'
|
|
|
|
f2 = nil
|
|
|
|
f1 = Fiber.new{ f2.resume }
|
|
|
|
f2 = Fiber.new{ f1.resume }
|
|
|
|
f1.transfer
|
2010-05-09 14:23:32 -04:00
|
|
|
}, '[ruby-dev:40833]'
|
2011-11-20 16:17:57 -05:00
|
|
|
assert_normal_exit %q{
|
|
|
|
require 'fiber'
|
|
|
|
Fiber.new{}.resume
|
|
|
|
1.times{Fiber.current.transfer}'
|
|
|
|
}
|
2010-05-09 13:32:45 -04:00
|
|
|
end
|
2010-11-03 13:08:25 -04:00
|
|
|
|
|
|
|
def test_resume_root_fiber
|
|
|
|
assert_raise(FiberError) do
|
|
|
|
Thread.new do
|
|
|
|
Fiber.current.resume
|
|
|
|
end.join
|
|
|
|
end
|
|
|
|
end
|
2011-05-15 08:41:40 -04:00
|
|
|
|
|
|
|
def test_gc_root_fiber
|
|
|
|
bug4612 = '[ruby-core:35891]'
|
|
|
|
|
|
|
|
assert_normal_exit %q{
|
|
|
|
require 'fiber'
|
|
|
|
GC.stress = true
|
|
|
|
Thread.start{ Fiber.current; nil }.join
|
|
|
|
GC.start
|
|
|
|
}, bug4612
|
|
|
|
end
|
2011-09-03 11:54:44 -04:00
|
|
|
|
|
|
|
def test_no_valid_cfp
|
|
|
|
bug5083 = '[ruby-dev:44208]'
|
|
|
|
error = assert_raise(RuntimeError) do
|
|
|
|
Fiber.new(&Module.method(:nesting)).resume
|
|
|
|
end
|
|
|
|
assert_equal("Can't call on top of Fiber or Thread", error.message, bug5083)
|
|
|
|
error = assert_raise(RuntimeError) do
|
|
|
|
Fiber.new(&Module.method(:undef_method)).resume(:to_s)
|
|
|
|
end
|
|
|
|
assert_equal("Can't call on top of Fiber or Thread", error.message, bug5083)
|
|
|
|
end
|
2011-11-09 05:02:22 -05:00
|
|
|
|
|
|
|
def test_prohibit_resume_transfered_fiber
|
|
|
|
assert_raise(FiberError){
|
|
|
|
root_fiber = Fiber.current
|
|
|
|
f = Fiber.new{
|
|
|
|
root_fiber.transfer
|
|
|
|
}
|
|
|
|
f.transfer
|
|
|
|
f.resume
|
|
|
|
}
|
|
|
|
assert_raise(FiberError){
|
|
|
|
g=nil
|
|
|
|
f=Fiber.new{
|
|
|
|
g.resume
|
|
|
|
g.resume
|
|
|
|
}
|
|
|
|
g=Fiber.new{
|
|
|
|
f.resume
|
|
|
|
f.resume
|
|
|
|
}
|
|
|
|
f.transfer
|
|
|
|
}
|
|
|
|
end
|
2012-02-15 09:00:11 -05:00
|
|
|
|
|
|
|
def test_fork_from_fiber
|
|
|
|
begin
|
|
|
|
Process.fork{}
|
|
|
|
rescue NotImplementedError
|
|
|
|
return
|
|
|
|
end
|
|
|
|
bug5700 = '[ruby-core:41456]'
|
|
|
|
pid = nil
|
|
|
|
assert_nothing_raised(bug5700) do
|
|
|
|
Fiber.new{ pid = fork {} }.resume
|
|
|
|
end
|
|
|
|
pid, status = Process.waitpid2(pid)
|
|
|
|
assert_equal(0, status.exitstatus, bug5700)
|
|
|
|
assert_equal(false, status.signaled?, bug5700)
|
|
|
|
end
|
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
|
|
|
end
|
|
|
|
|