From 8a0d53ac2b0d2af06d4c5fef87d1bb5913adbb05 Mon Sep 17 00:00:00 2001 From: ko1 Date: Wed, 22 Oct 2008 15:12:07 +0000 Subject: [PATCH] * cont.c: separate data structure between rb_fiber_t and rb_context_t (rb_fiber_t includes rb_context_t). rb_fiber_t has double linked list of fibers in same threads. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19890 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++ cont.c | 220 +++++++++++++++++++++++++++++++++++++----------------- version.h | 6 +- 3 files changed, 161 insertions(+), 71 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d5a7ae07e..553570ddec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Thu Oct 23 00:10:01 2008 Koichi Sasada + + * cont.c: separate data structure between rb_fiber_t and + rb_context_t (rb_fiber_t includes rb_context_t). + rb_fiber_t has double linked list of fibers in same threads. + Wed Oct 22 17:25:17 2008 Yukihiro Matsumoto * io.c (pipe_open): remove unnecessary flush before fork. diff --git a/cont.c b/cont.c index ad2c358264..6a4cabffcf 100644 --- a/cont.c +++ b/cont.c @@ -21,6 +21,7 @@ enum context_type { }; typedef struct rb_context_struct { + enum context_type type; VALUE self; VALUE value; VALUE *vm_stack; @@ -34,11 +35,22 @@ typedef struct rb_context_struct { rb_thread_t saved_thread; rb_jmpbuf_t jmpbuf; int machine_stack_size; - VALUE prev; - int alive; - enum context_type type; } rb_context_t; +enum fiber_status { + CREATED, + RUNNING, + TERMINATED, +}; + +typedef struct rb_fiber_struct { + rb_context_t cont; + VALUE prev; + enum fiber_status status; + struct rb_fiber_struct *prev_fiber; + struct rb_fiber_struct *next_fiber; +} rb_fiber_t; + static VALUE rb_cContinuation; static VALUE rb_cFiber; static VALUE rb_eFiberError; @@ -46,6 +58,9 @@ static VALUE rb_eFiberError; #define GetContPtr(obj, ptr) \ Data_Get_Struct(obj, rb_context_t, ptr) +#define GetFiberPtr(obj, ptr) \ + Data_Get_Struct(obj, rb_fiber_t, ptr) + NOINLINE(static VALUE cont_capture(volatile int *stat)); void rb_thread_mark(rb_thread_t *th); @@ -57,7 +72,6 @@ cont_mark(void *ptr) if (ptr) { rb_context_t *cont = ptr; rb_gc_mark(cont->value); - rb_gc_mark(cont->prev); rb_thread_mark(&cont->saved_thread); if (cont->vm_stack) { @@ -85,22 +99,69 @@ cont_free(void *ptr) RUBY_FREE_ENTER("cont"); if (ptr) { rb_context_t *cont = ptr; - RUBY_FREE_UNLESS_NULL(cont->saved_thread.stack); + RUBY_FREE_UNLESS_NULL(cont->saved_thread.stack); fflush(stdout); RUBY_FREE_UNLESS_NULL(cont->machine_stack); #ifdef __ia64 RUBY_FREE_UNLESS_NULL(cont->machine_register_stack); #endif RUBY_FREE_UNLESS_NULL(cont->vm_stack); - if (cont->type == FIBER_CONTEXT) { - st_free_table(cont->saved_thread.local_storage); - } - + /* free rb_cont_t or rb_fiber_t */ ruby_xfree(ptr); } RUBY_FREE_LEAVE("cont"); } +static void +fiber_mark(void *ptr) +{ + RUBY_MARK_ENTER("cont"); + if (ptr) { + rb_fiber_t *fib = ptr; + rb_gc_mark(fib->prev); + cont_mark(&fib->cont); + } + RUBY_MARK_LEAVE("cont"); +} + +static void +fiber_link_join(rb_fiber_t *fib) +{ + VALUE current_fibval = rb_fiber_current(); + rb_fiber_t *current_fib; + GetFiberPtr(current_fibval, current_fib); + + /* join fiber link */ + fib->next_fiber = current_fib->next_fiber; + fib->prev_fiber = current_fib; + current_fib->next_fiber->prev_fiber = fib; + current_fib->next_fiber = fib; +} + +static void +fiber_link_remove(rb_fiber_t *fib) +{ + fib->prev_fiber->next_fiber = fib->next_fiber; + fib->next_fiber->prev_fiber = fib->prev_fiber; +} + +static void +fiber_free(void *ptr) +{ + RUBY_FREE_ENTER("fiber"); + if (ptr) { + rb_fiber_t *fib = ptr; + + if (fib->cont.type != ROOT_FIBER_CONTEXT) { + st_free_table(fib->cont.saved_thread.local_storage); + } + fiber_link_remove(fib); + + cont_free(&fib->cont); + } + RUBY_FREE_LEAVE("fiber"); +} + static void cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) { @@ -151,21 +212,24 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) #endif } +static void +cont_init(rb_context_t *cont) +{ + rb_thread_t *th = GET_THREAD(); + + /* save thread context */ + cont->saved_thread = *th; +} + static rb_context_t * cont_new(VALUE klass) { rb_context_t *cont; volatile VALUE contval; - rb_thread_t *th = GET_THREAD(); contval = Data_Make_Struct(klass, rb_context_t, cont_mark, cont_free, cont); - cont->self = contval; - cont->alive = Qtrue; - - /* save thread context */ - cont->saved_thread = *th; - + cont_init(cont); return cont; } @@ -465,10 +529,6 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval) if (th->fiber != cont->saved_thread.fiber) { rb_raise(rb_eRuntimeError, "continuation called across fiber"); } - - if (!fcont->alive) { - rb_raise(rb_eRuntimeError, "continuation called dead fiber"); - } } cont->value = make_passing_arg(argc, argv); @@ -483,25 +543,32 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval) #define FIBER_VM_STACK_SIZE (4 * 1024) -static rb_context_t * +static rb_fiber_t * fiber_alloc(VALUE klass) { - rb_context_t *cont = cont_new(klass); + rb_fiber_t *fib; + volatile VALUE fibval = Data_Make_Struct(klass, rb_fiber_t, fiber_mark, fiber_free, fib); - cont->type = FIBER_CONTEXT; - cont->prev = Qnil; + fib->cont.self = fibval; + fib->cont.type = FIBER_CONTEXT; + cont_init(&fib->cont); + fib->prev = Qnil; + fib->status = CREATED; - return cont; + return fib; } static VALUE fiber_new(VALUE klass, VALUE proc) { - rb_context_t *cont = fiber_alloc(klass); - VALUE contval = cont->self; + rb_fiber_t *fib = fiber_alloc(klass); + VALUE fibval = fib->cont.self; + rb_context_t *cont = &fib->cont; rb_thread_t *th = &cont->saved_thread; - /* initialize */ + fiber_link_join(fib); + + /* initialize cont */ cont->vm_stack = 0; th->stack = 0; @@ -528,7 +595,7 @@ fiber_new(VALUE klass, VALUE proc) MEMCPY(&cont->jmpbuf, &th->root_jmpbuf, rb_jmpbuf_t, 1); - return contval; + return fibval; } VALUE @@ -546,11 +613,11 @@ rb_fiber_s_new(VALUE self) static VALUE return_fiber(void) { - rb_context_t *cont; + rb_fiber_t *fib; VALUE curr = rb_fiber_current(); - GetContPtr(curr, cont); + GetFiberPtr(curr, fib); - if (cont->prev == Qnil) { + if (fib->prev == Qnil) { rb_thread_t *th = GET_THREAD(); if (th->root_fiber != curr) { @@ -561,8 +628,8 @@ return_fiber(void) } } else { - VALUE prev = cont->prev; - cont->prev = Qnil; + VALUE prev = fib->prev; + fib->prev = Qnil; return prev; } } @@ -570,10 +637,10 @@ return_fiber(void) VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv); static void -rb_fiber_terminate(rb_context_t *cont) +rb_fiber_terminate(rb_fiber_t *fib) { - VALUE value = cont->value; - cont->alive = Qfalse; + VALUE value = fib->cont.value; + fib->status = TERMINATED; rb_fiber_transfer(return_fiber(), 1, &value); } @@ -581,12 +648,15 @@ void rb_fiber_start(void) { rb_thread_t *th = GET_THREAD(); + rb_fiber_t *fib; rb_context_t *cont; rb_proc_t *proc; VALUE args; int state; - GetContPtr(th->fiber, cont); + GetFiberPtr(th->fiber, fib); + cont = &fib->cont; + TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { GetProcPtr(cont->saved_thread.first_proc, proc); @@ -596,6 +666,7 @@ rb_fiber_start(void) th->local_lfp = proc->block.lfp; th->local_svar = Qnil; + fib->status = RUNNING; cont->value = vm_invoke_proc(th, proc, proc->block.self, 1, &args, 0); } TH_POP_TAG(); @@ -611,46 +682,57 @@ rb_fiber_start(void) RUBY_VM_SET_INTERRUPT(th); } - rb_fiber_terminate(cont); + rb_fiber_terminate(fib); rb_bug("rb_fiber_start: unreachable"); } +static rb_fiber_t * +root_fiber_alloc(rb_thread_t *th) +{ + rb_fiber_t *fib; + + /* no need to allocate vm stack */ + fib = fiber_alloc(rb_cFiber); + fib->cont.type = ROOT_FIBER_CONTEXT; + fib->prev_fiber = fib->next_fiber = fib; + + return fib; +} + VALUE rb_fiber_current() { rb_thread_t *th = GET_THREAD(); if (th->fiber == 0) { /* save root */ - rb_context_t *cont = fiber_alloc(rb_cFiber); - cont->type = ROOT_FIBER_CONTEXT; - th->root_fiber = th->fiber = cont->self; + rb_fiber_t *fib = root_fiber_alloc(th); + th->root_fiber = th->fiber = fib->cont.self; } return th->fiber; } static VALUE -fiber_store(rb_context_t *next_cont) +fiber_store(rb_fiber_t *next_fib) { rb_thread_t *th = GET_THREAD(); - rb_context_t *cont; + rb_fiber_t *fib; if (th->fiber) { - GetContPtr(th->fiber, cont); - cont->saved_thread = *th; + GetFiberPtr(th->fiber, fib); + fib->cont.saved_thread = *th; } else { /* create current fiber */ - cont = fiber_alloc(rb_cFiber); /* no need to allocate vm stack */ - cont->type = ROOT_FIBER_CONTEXT; - th->root_fiber = th->fiber = cont->self; + fib = root_fiber_alloc(th); + th->root_fiber = th->fiber = fib->cont.self; } - cont_save_machine_stack(th, cont); + cont_save_machine_stack(th, &fib->cont); - if (ruby_setjmp(cont->jmpbuf)) { + if (ruby_setjmp(fib->cont.jmpbuf)) { /* restored */ - GetContPtr(th->fiber, cont); - return cont->value; + GetFiberPtr(th->fiber, fib); + return fib->cont.value; } else { return Qundef; @@ -658,13 +740,15 @@ fiber_store(rb_context_t *next_cont) } static inline VALUE -fiber_switch(VALUE fib, int argc, VALUE *argv, int is_resume) +fiber_switch(VALUE fibval, int argc, VALUE *argv, int is_resume) { VALUE value; + rb_fiber_t *fib; rb_context_t *cont; rb_thread_t *th = GET_THREAD(); - GetContPtr(fib, cont); + GetFiberPtr(fibval, fib); + cont = &fib->cont; if (cont->saved_thread.self != th->self) { rb_raise(rb_eFiberError, "fiber called across threads"); @@ -672,18 +756,18 @@ fiber_switch(VALUE fib, int argc, VALUE *argv, int is_resume) else if (cont->saved_thread.trap_tag != th->trap_tag) { rb_raise(rb_eFiberError, "fiber called across trap"); } - else if (!cont->alive) { + else if (fib->status == TERMINATED) { rb_raise(rb_eFiberError, "dead fiber called"); } if (is_resume) { - cont->prev = rb_fiber_current(); + fib->prev = rb_fiber_current(); } cont->value = make_passing_arg(argc, argv); - if ((value = fiber_store(cont)) == Qundef) { - cont_restore_0(cont, &value); + if ((value = fiber_store(fib)) == Qundef) { + cont_restore_0(&fib->cont, &value); rb_bug("rb_fiber_resume: unreachable"); } @@ -699,16 +783,16 @@ rb_fiber_transfer(VALUE fib, int argc, VALUE *argv) } VALUE -rb_fiber_resume(VALUE fib, int argc, VALUE *argv) +rb_fiber_resume(VALUE fibval, int argc, VALUE *argv) { - rb_context_t *cont; - GetContPtr(fib, cont); + rb_fiber_t *fib; + GetFiberPtr(fibval, fib); - if (cont->prev != Qnil) { + if (fib->prev != Qnil) { rb_raise(rb_eFiberError, "double resume"); } - return fiber_switch(fib, argc, argv, 1); + return fiber_switch(fibval, argc, argv, 1); } VALUE @@ -718,11 +802,11 @@ rb_fiber_yield(int argc, VALUE *argv) } VALUE -rb_fiber_alive_p(VALUE fib) +rb_fiber_alive_p(VALUE fibval) { - rb_context_t *cont; - GetContPtr(fib, cont); - return cont->alive; + rb_fiber_t *fib; + GetFiberPtr(fibval, fib); + return fib->status != TERMINATED; } static VALUE diff --git a/version.h b/version.h index ec77a9abb2..7a65df9fb5 100644 --- a/version.h +++ b/version.h @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.9.0" -#define RUBY_RELEASE_DATE "2008-10-22" +#define RUBY_RELEASE_DATE "2008-10-23" #define RUBY_VERSION_CODE 190 -#define RUBY_RELEASE_CODE 20081022 +#define RUBY_RELEASE_CODE 20081023 #define RUBY_PATCHLEVEL 0 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_YEAR 2008 #define RUBY_RELEASE_MONTH 10 -#define RUBY_RELEASE_DAY 22 +#define RUBY_RELEASE_DAY 23 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[];