зеркало из https://github.com/github/ruby.git
* cont.c (Fiber#pass): rename to Fiber#yield. Block parameter
of fiber body receive first yield values. e.g.: Fiber.new{|x| p x}.yield(:ok) #=> :ok * cont.c: rename rb_context_t#retval to rb_context_t#value. * test/ruby/test_fiber.rb: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12425 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
66d4a354a8
Коммит
6b3ef2249c
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
Sat Jun 2 16:48:55 2007 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
* cont.c (Fiber#pass): rename to Fiber#yield. Block parameter
|
||||||
|
of fiber body receive first yield values.
|
||||||
|
e.g.: Fiber.new{|x| p x}.yield(:ok) #=> :ok
|
||||||
|
|
||||||
|
* cont.c: rename rb_context_t#retval to rb_context_t#value.
|
||||||
|
|
||||||
|
* test/ruby/test_fiber.rb: ditto.
|
||||||
|
|
||||||
Sat Jun 2 16:45:21 2007 Koichi Sasada <ko1@atdot.net>
|
Sat Jun 2 16:45:21 2007 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
* proc.c (Init_Proc): remove a line break.
|
* proc.c (Init_Proc): remove a line break.
|
||||||
|
|
70
cont.c
70
cont.c
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
typedef struct rb_context_struct {
|
typedef struct rb_context_struct {
|
||||||
VALUE self;
|
VALUE self;
|
||||||
VALUE retval;
|
VALUE value;
|
||||||
VALUE prev; /* for fiber */
|
VALUE prev; /* for fiber */
|
||||||
VALUE *vm_stack;
|
VALUE *vm_stack;
|
||||||
VALUE *machine_stack;
|
VALUE *machine_stack;
|
||||||
|
@ -30,6 +30,7 @@ typedef struct rb_context_struct {
|
||||||
|
|
||||||
VALUE rb_cCont;
|
VALUE rb_cCont;
|
||||||
VALUE rb_cFiber;
|
VALUE rb_cFiber;
|
||||||
|
VALUE rb_eFiberError;
|
||||||
|
|
||||||
#define GetContPtr(obj, ptr) \
|
#define GetContPtr(obj, ptr) \
|
||||||
Data_Get_Struct(obj, rb_context_t, ptr)
|
Data_Get_Struct(obj, rb_context_t, ptr)
|
||||||
|
@ -44,7 +45,7 @@ cont_mark(void *ptr)
|
||||||
MARK_REPORT_ENTER("cont");
|
MARK_REPORT_ENTER("cont");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
rb_context_t *cont = ptr;
|
rb_context_t *cont = ptr;
|
||||||
rb_gc_mark(cont->retval);
|
rb_gc_mark(cont->value);
|
||||||
rb_gc_mark(cont->prev);
|
rb_gc_mark(cont->prev);
|
||||||
|
|
||||||
rb_thread_mark(&cont->saved_thread);
|
rb_thread_mark(&cont->saved_thread);
|
||||||
|
@ -139,12 +140,12 @@ cont_capture(volatile int *stat)
|
||||||
cont_save_machine_stack(th, cont);
|
cont_save_machine_stack(th, cont);
|
||||||
|
|
||||||
if (ruby_setjmp(cont->jmpbuf)) {
|
if (ruby_setjmp(cont->jmpbuf)) {
|
||||||
VALUE retval;
|
VALUE value;
|
||||||
|
|
||||||
retval = cont->retval;
|
value = cont->value;
|
||||||
cont->retval = Qnil;
|
cont->value = Qnil;
|
||||||
*stat = 1;
|
*stat = 1;
|
||||||
return retval;
|
return value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*stat = 0;
|
*stat = 0;
|
||||||
|
@ -344,7 +345,7 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
|
||||||
rb_raise(rb_eRuntimeError, "continuation called across trap");
|
rb_raise(rb_eRuntimeError, "continuation called across trap");
|
||||||
}
|
}
|
||||||
|
|
||||||
cont->retval = make_passing_arg(argc, argv);
|
cont->value = make_passing_arg(argc, argv);
|
||||||
|
|
||||||
cont_restore_0(cont, (VALUE *)&cont);
|
cont_restore_0(cont, (VALUE *)&cont);
|
||||||
return Qnil; /* unreachable */
|
return Qnil; /* unreachable */
|
||||||
|
@ -357,11 +358,10 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
|
||||||
#define FIBER_STACK_SIZE (4 * 1024)
|
#define FIBER_STACK_SIZE (4 * 1024)
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_fiber_s_new(int argc, VALUE *argv, VALUE self)
|
rb_fiber_s_new(VALUE self)
|
||||||
{
|
{
|
||||||
rb_context_t *cont = cont_new(rb_cFiber);
|
rb_context_t *cont = cont_new(self);
|
||||||
rb_thread_t *th = &cont->saved_thread;
|
rb_thread_t *th = &cont->saved_thread;
|
||||||
volatile VALUE fval = cont->self;
|
|
||||||
|
|
||||||
/* initialize */
|
/* initialize */
|
||||||
cont->prev = Qnil;
|
cont->prev = Qnil;
|
||||||
|
@ -385,20 +385,19 @@ rb_fiber_s_new(int argc, VALUE *argv, VALUE self)
|
||||||
th->cfp->block_iseq = 0;
|
th->cfp->block_iseq = 0;
|
||||||
|
|
||||||
th->first_proc = rb_block_proc();
|
th->first_proc = rb_block_proc();
|
||||||
th->first_args = rb_ary_new4(argc, argv);
|
|
||||||
|
|
||||||
MEMCPY(&cont->jmpbuf, &th->root_jmpbuf, rb_jmpbuf_t, 1);
|
MEMCPY(&cont->jmpbuf, &th->root_jmpbuf, rb_jmpbuf_t, 1);
|
||||||
|
|
||||||
return cont->self;
|
return cont->self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE rb_fiber_pass(int argc, VALUE *args, VALUE fval);
|
static VALUE rb_fiber_yield(int argc, VALUE *args, VALUE fval);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rb_fiber_terminate(rb_context_t *cont)
|
rb_fiber_terminate(rb_context_t *cont)
|
||||||
{
|
{
|
||||||
rb_context_t *prev_cont;
|
rb_context_t *prev_cont;
|
||||||
VALUE retval = cont->retval;
|
VALUE value = cont->value;
|
||||||
|
|
||||||
GetContPtr(cont->prev, prev_cont);
|
GetContPtr(cont->prev, prev_cont);
|
||||||
|
|
||||||
|
@ -406,10 +405,10 @@ rb_fiber_terminate(rb_context_t *cont)
|
||||||
|
|
||||||
|
|
||||||
if (prev_cont->alive == Qfalse) {
|
if (prev_cont->alive == Qfalse) {
|
||||||
rb_fiber_pass(1, &retval, GET_THREAD()->root_fiber);
|
rb_fiber_yield(1, &value, GET_THREAD()->root_fiber);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_fiber_pass(1, &retval, cont->prev);
|
rb_fiber_yield(1, &value, cont->prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,12 +425,13 @@ rb_fiber_start(void)
|
||||||
if ((state = EXEC_TAG()) == 0) {
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
GetContPtr(th->fiber, cont);
|
GetContPtr(th->fiber, cont);
|
||||||
GetProcPtr(cont->saved_thread.first_proc, proc);
|
GetProcPtr(cont->saved_thread.first_proc, proc);
|
||||||
args = cont->saved_thread.first_args;
|
args = cont->value;
|
||||||
|
cont->value = Qnil;
|
||||||
th->errinfo = Qnil;
|
th->errinfo = Qnil;
|
||||||
th->local_lfp = proc->block.lfp;
|
th->local_lfp = proc->block.lfp;
|
||||||
th->local_svar = Qnil;
|
th->local_svar = Qnil;
|
||||||
cont->retval = th_invoke_proc(th, proc, proc->block.self,
|
|
||||||
RARRAY_LEN(args), RARRAY_PTR(args));
|
cont->value = th_invoke_proc(th, proc, proc->block.self, 1, &args);
|
||||||
}
|
}
|
||||||
TH_POP_TAG();
|
TH_POP_TAG();
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ cont_store(rb_context_t *next_cont)
|
||||||
if (ruby_setjmp(cont->jmpbuf)) {
|
if (ruby_setjmp(cont->jmpbuf)) {
|
||||||
/* restored */
|
/* restored */
|
||||||
GetContPtr(th->fiber, cont);
|
GetContPtr(th->fiber, cont);
|
||||||
return cont->retval;
|
return cont->value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Qundef;
|
return Qundef;
|
||||||
|
@ -486,29 +486,32 @@ cont_store(rb_context_t *next_cont)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_fiber_pass(int argc, VALUE *argv, VALUE fval)
|
rb_fiber_yield(int argc, VALUE *argv, VALUE fval)
|
||||||
{
|
{
|
||||||
VALUE retval;
|
VALUE value;
|
||||||
rb_context_t *cont;
|
rb_context_t *cont;
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
GetContPtr(fval, cont);
|
GetContPtr(fval, cont);
|
||||||
|
|
||||||
if (cont->saved_thread.self != th->self) {
|
if (cont->saved_thread.self != th->self) {
|
||||||
rb_raise(rb_eRuntimeError, "fiber called across threads");
|
rb_raise(rb_eFiberError, "fiber called across threads");
|
||||||
}
|
}
|
||||||
if (cont->saved_thread.trap_tag != th->trap_tag) {
|
if (cont->saved_thread.trap_tag != th->trap_tag) {
|
||||||
rb_raise(rb_eRuntimeError, "fiber called across trap");
|
rb_raise(rb_eFiberError, "fiber called across trap");
|
||||||
|
}
|
||||||
|
if (!cont->alive) {
|
||||||
|
rb_raise(rb_eFiberError, "dead fiber called");
|
||||||
}
|
}
|
||||||
|
|
||||||
cont->retval = make_passing_arg(argc, argv);
|
cont->value = make_passing_arg(argc, argv);
|
||||||
|
|
||||||
if ((retval = cont_store(cont)) == Qundef) {
|
if ((value = cont_store(cont)) == Qundef) {
|
||||||
cont_restore_0(cont, (VALUE *)&cont);
|
cont_restore_0(cont, (VALUE *)&cont);
|
||||||
rb_bug("rb_fiber_pass: unreachable");
|
rb_bug("rb_fiber_yield: unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -540,9 +543,9 @@ rb_fiber_s_prev(VALUE klass)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_fiber_s_pass(int argc, VALUE *argv, VALUE fval)
|
rb_fiber_s_yield(int argc, VALUE *argv, VALUE fval)
|
||||||
{
|
{
|
||||||
return rb_fiber_pass(argc, argv, rb_fiber_s_prev(Qnil));
|
return rb_fiber_yield(argc, argv, rb_fiber_s_prev(Qnil));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -557,14 +560,15 @@ Init_Cont(void)
|
||||||
|
|
||||||
rb_cFiber = rb_define_class("Fiber", rb_cObject);
|
rb_cFiber = rb_define_class("Fiber", rb_cObject);
|
||||||
rb_undef_alloc_func(rb_cFiber);
|
rb_undef_alloc_func(rb_cFiber);
|
||||||
rb_define_method(rb_cFiber, "pass", rb_fiber_pass, -1);
|
rb_define_method(rb_cFiber, "yield", rb_fiber_yield, -1);
|
||||||
rb_define_method(rb_cFiber, "prev", rb_fiber_prev, 0);
|
rb_define_method(rb_cFiber, "prev", rb_fiber_prev, 0);
|
||||||
rb_define_method(rb_cFiber, "alive?", rb_fiber_alive_p, 0);
|
rb_define_method(rb_cFiber, "alive?", rb_fiber_alive_p, 0);
|
||||||
|
|
||||||
rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
|
rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
|
||||||
rb_define_singleton_method(rb_cFiber, "prev", rb_fiber_s_prev, 0);
|
rb_define_singleton_method(rb_cFiber, "prev", rb_fiber_s_prev, 0);
|
||||||
rb_define_singleton_method(rb_cFiber, "pass", rb_fiber_s_pass, -1);
|
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
|
||||||
rb_define_singleton_method(rb_cFiber, "new", rb_fiber_s_new, -1);
|
rb_define_singleton_method(rb_cFiber, "new", rb_fiber_s_new, 0);
|
||||||
rb_define_singleton_method(rb_cFiber, "start", rb_fiber_s_new, -1);
|
|
||||||
|
rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,25 +4,27 @@ class TestFiber < Test::Unit::TestCase
|
||||||
def test_normal
|
def test_normal
|
||||||
f = Fiber.current
|
f = Fiber.current
|
||||||
assert_equal(:ok2,
|
assert_equal(:ok2,
|
||||||
Fiber.new(:ok1){|e|
|
Fiber.new{|e|
|
||||||
assert_equal(:ok1, e)
|
assert_equal(:ok1, e)
|
||||||
assert_equal(f, Fiber.prev)
|
assert_equal(f, Fiber.prev)
|
||||||
Fiber.pass :ok2
|
Fiber.yield :ok2
|
||||||
}.pass)
|
}.yield(:ok1)
|
||||||
|
)
|
||||||
|
assert_equal([:a, :b], Fiber.new{|a, b| [a, b]}.yield(:a, :b))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_term
|
def test_term
|
||||||
assert_equal(:ok, Fiber.new{:ok}.pass)
|
assert_equal(:ok, Fiber.new{:ok}.yield)
|
||||||
assert_equal([:a, :b, :c, :d, :e],
|
assert_equal([:a, :b, :c, :d, :e],
|
||||||
Fiber.new{
|
Fiber.new{
|
||||||
Fiber.new{
|
Fiber.new{
|
||||||
Fiber.new{
|
Fiber.new{
|
||||||
Fiber.new{
|
Fiber.new{
|
||||||
[:a]
|
[:a]
|
||||||
}.pass + [:b]
|
}.yield + [:b]
|
||||||
}.pass + [:c]
|
}.yield + [:c]
|
||||||
}.pass + [:d]
|
}.yield + [:d]
|
||||||
}.pass + [:e])
|
}.yield + [:e])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_many_fibers
|
def test_many_fibers
|
||||||
|
@ -33,7 +35,7 @@ class TestFiber < Test::Unit::TestCase
|
||||||
assert_equal(max,
|
assert_equal(max,
|
||||||
max.times{|i|
|
max.times{|i|
|
||||||
Fiber.new{
|
Fiber.new{
|
||||||
}.pass
|
}.yield
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -42,9 +44,14 @@ class TestFiber < Test::Unit::TestCase
|
||||||
assert_raise(ArgumentError){
|
assert_raise(ArgumentError){
|
||||||
Fiber.new # Fiber without block
|
Fiber.new # Fiber without block
|
||||||
}
|
}
|
||||||
assert_raise(RuntimeError){
|
assert_raise(FiberError){
|
||||||
f = Fiber.new{}
|
f = Fiber.new{}
|
||||||
Thread.new{f.pass}.join # Fiber passing across thread
|
Thread.new{f.yield}.join # Fiber yielding across thread
|
||||||
|
}
|
||||||
|
assert_raise(FiberError){
|
||||||
|
f = Fiber.new{}
|
||||||
|
f.yield
|
||||||
|
f.yield
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,14 +59,14 @@ class TestFiber < Test::Unit::TestCase
|
||||||
ary = []
|
ary = []
|
||||||
f2 = nil
|
f2 = nil
|
||||||
f1 = Fiber.new{
|
f1 = Fiber.new{
|
||||||
ary << f2.pass(:foo)
|
ary << f2.yield(:foo)
|
||||||
:bar
|
:bar
|
||||||
}
|
}
|
||||||
f2 = Fiber.new{
|
f2 = Fiber.new{
|
||||||
ary << f1.pass(:baz)
|
ary << f1.yield(:baz)
|
||||||
:ok
|
:ok
|
||||||
}
|
}
|
||||||
assert_equal(:ok, f1.pass)
|
assert_equal(:ok, f1.yield)
|
||||||
assert_equal([:baz, :bar], ary)
|
assert_equal([:baz, :bar], ary)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче