From fbf899e0204808fa2a01ade8ca8b69feb1bcc479 Mon Sep 17 00:00:00 2001 From: ko1 Date: Thu, 26 Oct 2017 08:32:49 +0000 Subject: Use rb_execution_context_t instead of rb_thread_t to represent execution context [Feature #14038] * vm_core.h (rb_thread_t): rb_thread_t::ec is now a pointer. There are many code using `th` to represent execution context (such as cfp, VM stack and so on). To access `ec`, they need to use `th->ec->...` (adding one indirection) so that we need to replace them by passing `ec` instead of `th`. * vm_core.h (GET_EC()): introduced to access current ec. Also remove `ruby_current_thread` global variable. * cont.c (rb_context_t): introduce rb_context_t::thread_ptr instead of rb_context_t::thread_value. * cont.c (ec_set_vm_stack): added to update vm_stack explicitly. * cont.c (ec_switch): added to switch ec explicitly. * cont.c (rb_fiber_close): added to terminate fibers explicitly. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60440 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- cont.c | 375 +++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 248 insertions(+), 127 deletions(-) (limited to 'cont.c') diff --git a/cont.c b/cont.c index df4ac789bd..2d9cf8d07f 100644 --- a/cont.c +++ b/cont.c @@ -83,8 +83,8 @@ enum context_type { struct cont_saved_vm_stack { VALUE *ptr; #ifdef CAPTURE_JUST_VALID_VM_STACK - size_t slen; /* length of stack (head of th->ec.vm_stack) */ - size_t clen; /* length of control frames (tail of th->ec.vm_stack) */ + size_t slen; /* length of stack (head of th->ec->vm_stack) */ + size_t clen; /* length of control frames (tail of th->ec->vm_stack) */ #endif }; @@ -110,7 +110,7 @@ typedef struct rb_context_struct { rb_jmpbuf_t jmpbuf; rb_ensure_entry_t *ensure_array; rb_ensure_list_t *ensure_list; - VALUE thread_value; + rb_thread_t *thread_ptr; } rb_context_t; @@ -189,15 +189,62 @@ fiber_status_name(enum fiber_status s) return NULL; } +static void +fiber_verify(const rb_fiber_t *fib) +{ +#if VM_CHECK_MODE > 0 + VM_ASSERT(fib->cont.saved_ec.fiber == fib); + + switch (fib->status) { + case FIBER_RESUMED: + VM_ASSERT(fib->cont.saved_ec.vm_stack != NULL); + break; + case FIBER_SUSPENDED: + VM_ASSERT(fib->cont.saved_ec.vm_stack != NULL); + break; + case FIBER_CREATED: + case FIBER_TERMINATED: + /* TODO */ + break; + default: + VM_UNREACHABLE(fiber_verify); + } +#endif +} + +#if VM_CHECK_MODE > 0 +void +rb_ec_verify(const rb_execution_context_t *ec) +{ + /* TODO */ +} +#endif + static void fiber_status_set(const rb_fiber_t *fib, enum fiber_status s) { if (0) fprintf(stderr, "fib: %p, status: %s -> %s\n", fib, fiber_status_name(fib->status), fiber_status_name(s)); VM_ASSERT(!FIBER_TERMINATED_P(fib)); VM_ASSERT(fib->status != s); + fiber_verify(fib); *((enum fiber_status *)&fib->status) = s; } +void +ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size) +{ + *(VALUE **)(&ec->vm_stack) = stack; + *(size_t *)(&ec->vm_stack_size) = size; +} + +static inline void +ec_switch(rb_thread_t *th, rb_fiber_t *fib) +{ + rb_execution_context_t *ec = &fib->cont.saved_ec; + ruby_current_execution_context_ptr = th->ec = ec; + VM_ASSERT(ec->fiber->cont.self == 0 || ec->vm_stack != NULL); +} + static const rb_data_type_t cont_data_type, fiber_data_type; static VALUE rb_cContinuation; static VALUE rb_cFiber; @@ -214,13 +261,13 @@ static VALUE rb_eFiberError; NOINLINE(static VALUE cont_capture(volatile int *volatile stat)); #define THREAD_MUST_BE_RUNNING(th) do { \ - if (!(th)->ec.tag) rb_raise(rb_eThreadError, "not running thread"); \ + if (!(th)->ec->tag) rb_raise(rb_eThreadError, "not running thread"); \ } while (0) static VALUE cont_thread_value(const rb_context_t *cont) { - return cont->thread_value; + return cont->thread_ptr->self; } static void @@ -252,10 +299,9 @@ cont_mark(void *ptr) } else { /* fiber */ - const rb_thread_t *th = rb_thread_ptr(cont_thread_value(cont)); const rb_fiber_t *fib = (rb_fiber_t*)cont; - if ((th->ec.fiber != fib) && !FIBER_TERMINATED_P(fib)) { + if (!FIBER_TERMINATED_P(fib)) { rb_gc_mark_locations(cont->machine.stack, cont->machine.stack + cont->machine.stack_size); } @@ -277,7 +323,8 @@ cont_free(void *ptr) rb_context_t *cont = ptr; RUBY_FREE_ENTER("cont"); - RUBY_FREE_UNLESS_NULL(cont->saved_ec.vm_stack); + ruby_xfree(cont->saved_ec.vm_stack); + #if FIBER_USE_NATIVE if (cont->type == CONTINUATION_CONTEXT) { /* cont */ @@ -287,22 +334,19 @@ cont_free(void *ptr) else { /* fiber */ const rb_fiber_t *fib = (rb_fiber_t*)cont; - const rb_thread_t *const th = GET_THREAD(); #ifdef _WIN32 - if (th && th->ec.fiber != fib && cont->type != ROOT_FIBER_CONTEXT) { + if (cont->type != ROOT_FIBER_CONTEXT) { /* don't delete root fiber handle */ if (fib->fib_handle) { DeleteFiber(fib->fib_handle); } } #else /* not WIN32 */ - if (th && th->ec.fiber != fib) { - if (fib->ss_sp) { - if (cont->type == ROOT_FIBER_CONTEXT) { - rb_bug("Illegal root fiber parameter"); - } - munmap((void*)fib->ss_sp, fib->ss_size); + if (fib->ss_sp != NULL) { + if (cont->type == ROOT_FIBER_CONTEXT) { + rb_bug("Illegal root fiber parameter"); } + munmap((void*)fib->ss_sp, fib->ss_size); } else { /* It may reached here when finalize */ @@ -352,32 +396,21 @@ cont_memsize(const void *ptr) return size; } -static void -fiber_verify(const rb_fiber_t *fib) +rb_thread_t * +rb_fiberptr_thread_ptr(const rb_fiber_t *fib) { -#if VM_CHECK_MODE > 0 - switch (fib->status) { - case FIBER_RESUMED: - VM_ASSERT(fib->cont.saved_ec.vm_stack == NULL); - break; - case FIBER_SUSPENDED: - VM_ASSERT(fib->cont.saved_ec.vm_stack != NULL); - break; - case FIBER_CREATED: - case FIBER_TERMINATED: - /* TODO */ - break; - default: - VM_UNREACHABLE(fiber_verify); - } -#endif + return fib->cont.thread_ptr; } void rb_fiber_mark_self(const rb_fiber_t *fib) { - if (fib) + if (fib->cont.self) { rb_gc_mark(fib->cont.self); + } + else { + rb_execution_context_mark(&fib->cont.saved_ec); + } } static void @@ -387,7 +420,17 @@ fiber_mark(void *ptr) RUBY_MARK_ENTER("cont"); fiber_verify(fib); rb_gc_mark(fib->first_proc); - rb_fiber_mark_self(fib->prev); + if (fib->prev) rb_fiber_mark_self(fib->prev); + +#if !FIBER_USE_NATIVE + if (fib->status == FIBER_TERMINATED) { + /* FIBER_TERMINATED fiber should not mark machine stack */ + if (fib->cont.saved_ec.machine.stack_end != NULL) { + fib->cont.saved_ec.machine.stack_end = NULL; + } + } +#endif + cont_mark(&fib->cont); RUBY_MARK_LEAVE("cont"); } @@ -397,8 +440,7 @@ fiber_free(void *ptr) { rb_fiber_t *fib = ptr; RUBY_FREE_ENTER("fiber"); - if (fib->cont.type != ROOT_FIBER_CONTEXT && - fib->cont.saved_ec.local_storage) { + if (fib->cont.saved_ec.local_storage) { st_free_table(fib->cont.saved_ec.local_storage); } @@ -437,18 +479,18 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) { size_t size; - SET_MACHINE_STACK_END(&th->ec.machine.stack_end); + SET_MACHINE_STACK_END(&th->ec->machine.stack_end); #ifdef __ia64 th->machine.register_stack_end = rb_ia64_bsp(); #endif - if (th->ec.machine.stack_start > th->ec.machine.stack_end) { - size = cont->machine.stack_size = th->ec.machine.stack_start - th->ec.machine.stack_end; - cont->machine.stack_src = th->ec.machine.stack_end; + if (th->ec->machine.stack_start > th->ec->machine.stack_end) { + size = cont->machine.stack_size = th->ec->machine.stack_start - th->ec->machine.stack_end; + cont->machine.stack_src = th->ec->machine.stack_end; } else { - size = cont->machine.stack_size = th->ec.machine.stack_end - th->ec.machine.stack_start; - cont->machine.stack_src = th->ec.machine.stack_start; + size = cont->machine.stack_size = th->ec->machine.stack_end - th->ec->machine.stack_start; + cont->machine.stack_src = th->ec->machine.stack_start; } if (cont->machine.stack) { @@ -490,7 +532,7 @@ cont_save_thread(rb_context_t *cont, rb_thread_t *th) VM_ASSERT(th->status == THREAD_RUNNABLE); /* save thread context */ - *sec = th->ec; + *sec = *th->ec; /* saved_thread->machine.stack_end should be NULL */ /* because it may happen GC afterward */ @@ -507,7 +549,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th) { /* save thread context */ cont_save_thread(cont, th); - cont->thread_value = th->self; + cont->thread_ptr = th; cont->saved_ec.local_storage = NULL; cont->saved_ec.local_storage_recursive_hash = Qnil; cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil; @@ -527,13 +569,40 @@ cont_new(VALUE klass) return cont; } +#if 0 +void +show_vm_stack(const rb_execution_context_t *ec) +{ + VALUE *p = ec->vm_stack; + while (p < ec->cfp->sp) { + fprintf(stderr, "%3d ", (int)(p - ec->vm_stack)); + rb_obj_info_dump(*p); + p++; + } +} + +void +show_vm_pcs(const rb_control_frame_t *cfp, + const rb_control_frame_t *end_of_cfp) +{ + int i=0; + while (cfp != end_of_cfp) { + int pc = 0; + if (cfp->iseq) { + pc = cfp->pc - cfp->iseq->body->iseq_encoded; + } + fprintf(stderr, "%2d pc: %d\n", i++, pc); + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + } +} +#endif static VALUE cont_capture(volatile int *volatile stat) { rb_context_t *volatile cont; rb_thread_t *th = GET_THREAD(); volatile VALUE contval; - rb_execution_context_t *ec = &th->ec; + const rb_execution_context_t *ec = th->ec; THREAD_MUST_BE_RUNNING(th); rb_vm_stack_to_heap(th); @@ -544,15 +613,18 @@ cont_capture(volatile int *volatile stat) cont->saved_vm_stack.slen = ec->cfp->sp - ec->vm_stack; cont->saved_vm_stack.clen = ec->vm_stack + ec->vm_stack_size - (VALUE*)ec->cfp; cont->saved_vm_stack.ptr = ALLOC_N(VALUE, cont->saved_vm_stack.slen + cont->saved_vm_stack.clen); - MEMCPY(cont->saved_vm_stack.ptr, ec->vm_stack, VALUE, cont->saved_vm_stack.slen); + MEMCPY(cont->saved_vm_stack.ptr, + ec->vm_stack, + VALUE, cont->saved_vm_stack.slen); MEMCPY(cont->saved_vm_stack.ptr + cont->saved_vm_stack.slen, - (VALUE*)ec->cfp, VALUE, cont->saved_vm_stack.clen); + (VALUE*)ec->cfp, + VALUE, + cont->saved_vm_stack.clen); #else cont->saved_vm_stack.ptr = ALLOC_N(VALUE, ec->vm_stack_size); MEMCPY(cont->saved_vm_stack.ptr, ec->vm_stack, VALUE, ec->vm_stack_size); #endif - cont->saved_ec.vm_stack = NULL; - + ec_set_vm_stack(&cont->saved_ec, NULL, 0); cont_save_machine_stack(th, cont); /* backup ensure_list to array for search in another context */ @@ -560,10 +632,10 @@ cont_capture(volatile int *volatile stat) rb_ensure_list_t *p; int size = 0; rb_ensure_entry_t *entry; - for (p=th->ec.ensure_list; p; p=p->next) + for (p=th->ec->ensure_list; p; p=p->next) size++; entry = cont->ensure_array = ALLOC_N(rb_ensure_entry_t,size+1); - for (p=th->ec.ensure_list; p; p=p->next) { + for (p=th->ec->ensure_list; p; p=p->next) { if (!p->entry.marker) p->entry.marker = rb_ary_tmp_new(0); /* dummy object */ *entry++ = p->entry; @@ -590,10 +662,8 @@ cont_capture(volatile int *volatile stat) static inline void fiber_restore_thread(rb_thread_t *th, rb_fiber_t *fib) { - th->ec = fib->cont.saved_ec; - fib->cont.saved_ec.vm_stack = NULL; - - VM_ASSERT(th->ec.vm_stack != NULL); + ec_switch(th, fib); + VM_ASSERT(th->ec->fiber == fib); } static inline void @@ -605,36 +675,44 @@ cont_restore_thread(rb_context_t *cont) if (cont->type == CONTINUATION_CONTEXT) { /* continuation */ rb_execution_context_t *sec = &cont->saved_ec; - const rb_fiber_t *fib; + rb_fiber_t *fib = NULL; - fib = th->ec.fiber = sec->fiber; - if (fib == NULL) fib = th->root_fiber; + if (sec->fiber != NULL) { + fib = sec->fiber; + } + else if (th->root_fiber) { + fib = th->root_fiber; + } - if (fib && fib->cont.saved_ec.vm_stack) { - th->ec.vm_stack_size = fib->cont.saved_ec.vm_stack_size; - th->ec.vm_stack = fib->cont.saved_ec.vm_stack; + if (fib && th->ec != &fib->cont.saved_ec) { + ec_switch(th, fib); } + + /* copy vm stack */ #ifdef CAPTURE_JUST_VALID_VM_STACK - MEMCPY(th->ec.vm_stack, cont->saved_vm_stack.ptr, VALUE, cont->saved_vm_stack.slen); - MEMCPY(th->ec.vm_stack + sec->vm_stack_size - cont->saved_vm_stack.clen, - cont->saved_vm_stack.ptr + cont->saved_vm_stack.slen, VALUE, cont->saved_vm_stack.clen); + MEMCPY(th->ec->vm_stack, + cont->saved_vm_stack.ptr, + VALUE, cont->saved_vm_stack.slen); + MEMCPY(th->ec->vm_stack + th->ec->vm_stack_size - cont->saved_vm_stack.clen, + cont->saved_vm_stack.ptr + cont->saved_vm_stack.slen, + VALUE, cont->saved_vm_stack.clen); #else - MEMCPY(th->ec.vm_stack, cont->saved_vm_stack.ptr, VALUE, sec->vm_stack_size); + MEMCPY(th->ec->vm_stack, cont->saved_vm_stack.ptr, VALUE, sec->vm_stack_size); #endif - /* other members of ec */ - th->ec.cfp = sec->cfp; - th->ec.safe_level = sec->safe_level; - th->ec.raised_flag = sec->raised_flag; - th->ec.tag = sec->tag; - th->ec.protect_tag = sec->protect_tag; - th->ec.root_lep = sec->root_lep; - th->ec.root_svar = sec->root_svar; - th->ec.ensure_list = sec->ensure_list; - th->ec.errinfo = sec->errinfo; - th->ec.trace_arg = sec->trace_arg; - - VM_ASSERT(th->ec.vm_stack != NULL); + + th->ec->cfp = sec->cfp; + th->ec->safe_level = sec->safe_level; + th->ec->raised_flag = sec->raised_flag; + th->ec->tag = sec->tag; + th->ec->protect_tag = sec->protect_tag; + th->ec->root_lep = sec->root_lep; + th->ec->root_svar = sec->root_svar; + th->ec->ensure_list = sec->ensure_list; + th->ec->errinfo = sec->errinfo; + th->ec->trace_arg = sec->trace_arg; + + VM_ASSERT(th->ec->vm_stack != NULL); } else { /* fiber */ @@ -651,7 +729,7 @@ fiber_set_stack_location(void) VALUE *ptr; SET_MACHINE_STACK_END(&ptr); - th->ec.machine.stack_start = (void*)(((VALUE)ptr & RB_PAGE_MASK) + STACK_UPPER((void *)&ptr, 0, RB_PAGE_SIZE)); + th->ec->machine.stack_start = (void*)(((VALUE)ptr & RB_PAGE_MASK) + STACK_UPPER((void *)&ptr, 0, RB_PAGE_SIZE)); } static VOID CALLBACK @@ -762,19 +840,19 @@ fiber_setcontext(rb_fiber_t *newfib, rb_fiber_t *oldfib) /* save oldfib's machine stack / TODO: is it needed? */ if (!FIBER_TERMINATED_P(oldfib)) { STACK_GROW_DIR_DETECTION; - SET_MACHINE_STACK_END(&th->ec.machine.stack_end); + SET_MACHINE_STACK_END(&th->ec->machine.stack_end); if (STACK_DIR_UPPER(0, 1)) { - oldfib->cont.machine.stack_size = th->ec.machine.stack_start - th->ec.machine.stack_end; - oldfib->cont.machine.stack = th->ec.machine.stack_end; + oldfib->cont.machine.stack_size = th->ec->machine.stack_start - th->ec->machine.stack_end; + oldfib->cont.machine.stack = th->ec->machine.stack_end; } else { - oldfib->cont.machine.stack_size = th->ec.machine.stack_end - th->ec.machine.stack_start; - oldfib->cont.machine.stack = th->ec.machine.stack_start; + oldfib->cont.machine.stack_size = th->ec->machine.stack_end - th->ec->machine.stack_start; + oldfib->cont.machine.stack = th->ec->machine.stack_start; } } /* exchange machine_stack_start between oldfib and newfib */ - oldfib->cont.saved_ec.machine.stack_start = th->ec.machine.stack_start; + oldfib->cont.saved_ec.machine.stack_start = th->ec->machine.stack_start; /* oldfib->machine.stack_end should be NULL */ oldfib->cont.saved_ec.machine.stack_end = NULL; @@ -1128,15 +1206,15 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval) if (cont_thread_value(cont) != th->self) { rb_raise(rb_eRuntimeError, "continuation called across threads"); } - if (cont->saved_ec.protect_tag != th->ec.protect_tag) { + if (cont->saved_ec.protect_tag != th->ec->protect_tag) { rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier"); } if (cont->saved_ec.fiber) { - if (th->ec.fiber != cont->saved_ec.fiber) { + if (th->ec->fiber != cont->saved_ec.fiber) { rb_raise(rb_eRuntimeError, "continuation called across fiber"); } } - rollback_ensure_stack(contval, th->ec.ensure_list, cont->ensure_array); + rollback_ensure_stack(contval, th->ec->ensure_list, cont->ensure_array); cont->argc = argc; cont->value = make_passing_arg(argc, argv); @@ -1270,15 +1348,13 @@ fiber_init(VALUE fibval, VALUE proc) rb_context_t *cont = &fib->cont; rb_execution_context_t *sec = &cont->saved_ec; rb_thread_t *cth = GET_THREAD(); + size_t fib_stack_size = cth->vm->default_params.fiber_vm_stack_size / sizeof(VALUE); /* initialize cont */ cont->saved_vm_stack.ptr = NULL; + ec_set_vm_stack(sec, NULL, 0); - sec->vm_stack = NULL; - sec->vm_stack_size = 0; - - sec->vm_stack_size = cth->vm->default_params.fiber_vm_stack_size / sizeof(VALUE); - sec->vm_stack = ALLOC_N(VALUE, sec->vm_stack_size); + ec_set_vm_stack(sec, ALLOC_N(VALUE, fib_stack_size), fib_stack_size); sec->cfp = (void *)(sec->vm_stack + sec->vm_stack_size); rb_vm_push_frame(sec, @@ -1324,11 +1400,12 @@ static void rb_fiber_terminate(rb_fiber_t *fib); void rb_fiber_start(void) { - rb_thread_t *th = GET_THREAD(); - rb_fiber_t *fib = th->ec.fiber; + rb_thread_t * volatile th = GET_THREAD(); + rb_fiber_t *fib = th->ec->fiber; rb_proc_t *proc; enum ruby_tag_type state; + VM_ASSERT(th->ec == ruby_current_execution_context_ptr); VM_ASSERT(FIBER_RESUMED_P(fib)); TH_PUSH_TAG(th); @@ -1339,9 +1416,9 @@ rb_fiber_start(void) GetProcPtr(fib->first_proc, proc); argv = (argc = cont->argc) > 1 ? RARRAY_CONST_PTR(args) : &args; cont->value = Qnil; - th->ec.errinfo = Qnil; - th->ec.root_lep = rb_vm_proc_local_ep(fib->first_proc); - th->ec.root_svar = Qfalse; + th->ec->errinfo = Qnil; + th->ec->root_lep = rb_vm_proc_local_ep(fib->first_proc); + th->ec->root_svar = Qfalse; EXEC_EVENT_HOOK(th, RUBY_EVENT_FIBER_SWITCH, th->self, 0, 0, 0, Qnil); cont->value = rb_vm_invoke_proc(th, proc, argc, argv, VM_BLOCK_HANDLER_NONE); @@ -1352,10 +1429,10 @@ rb_fiber_start(void) VM_ASSERT(FIBER_RESUMED_P(fib)); if (state == TAG_RAISE || state == TAG_FATAL) { - rb_threadptr_pending_interrupt_enque(th, th->ec.errinfo); + rb_threadptr_pending_interrupt_enque(th, th->ec->errinfo); } else { - VALUE err = rb_vm_make_jump_tag_but_local_jump(state, th->ec.errinfo); + VALUE err = rb_vm_make_jump_tag_but_local_jump(state, th->ec->errinfo); if (!NIL_P(err)) rb_threadptr_pending_interrupt_enque(th, err); } @@ -1369,30 +1446,54 @@ rb_fiber_start(void) static rb_fiber_t * root_fiber_alloc(rb_thread_t *th) { - rb_fiber_t *fib; - /* no need to allocate vm stack */ - fib = fiber_t_alloc(fiber_alloc(rb_cFiber)); - fib->cont.type = ROOT_FIBER_CONTEXT; + VALUE fibval = fiber_alloc(rb_cFiber); + rb_fiber_t *fib = th->ec->fiber; + + VM_ASSERT(DATA_PTR(fibval) == NULL); + VM_ASSERT(fib->cont.type == ROOT_FIBER_CONTEXT); + VM_ASSERT(fib->status == FIBER_RESUMED); + + th->root_fiber = fib; + DATA_PTR(fibval) = fib; + fib->cont.self = fibval; #if FIBER_USE_NATIVE #ifdef _WIN32 - fib->fib_handle = ConvertThreadToFiber(0); + if (fib->fib_handle == 0) { + fib->fib_handle = ConvertThreadToFiber(0); + } #endif #endif - fiber_status_set(fib, FIBER_RESUMED); /* skip CREATED */ - th->root_fiber = th->ec.fiber = fib; return fib; } +void +rb_threadptr_root_fiber_setup(rb_thread_t *th) +{ + rb_fiber_t *fib = ruby_mimmalloc(sizeof(rb_fiber_t)); + MEMZERO(fib, rb_fiber_t, 1); + fib->cont.type = ROOT_FIBER_CONTEXT; + fib->cont.saved_ec.fiber = fib; + fib->cont.thread_ptr = th; + fiber_status_set(fib, FIBER_RESUMED); /* skip CREATED */ + th->ec = &fib->cont.saved_ec; + th->root_fiber = th->ec->fiber = fib; +#if FIBER_USE_NATIVE +#ifdef _WIN32 + if (fib->fib_handle == 0) { + fib->fib_handle = ConvertThreadToFiber(0); + } +#endif +#endif +} + static inline rb_fiber_t* fiber_current(void) { rb_thread_t *th = GET_THREAD(); - if (th->ec.fiber == NULL) { - rb_fiber_t *fib = root_fiber_alloc(th); - /* Running thread object has stack management responsibility */ - fib->cont.saved_ec.vm_stack = NULL; + if (th->ec->fiber->cont.self == 0) { + root_fiber_alloc(th); } - return th->ec.fiber; + return th->ec->fiber; } static inline rb_fiber_t* @@ -1426,9 +1527,8 @@ fiber_store(rb_fiber_t *next_fib, rb_thread_t *th) { rb_fiber_t *fib; - if (th->ec.fiber != NULL) { - fib = th->ec.fiber; - cont_save_thread(&fib->cont, th); + if (th->ec->fiber != NULL) { + fib = th->ec->fiber; } else { /* create root fiber */ @@ -1475,14 +1575,14 @@ fiber_store(rb_fiber_t *next_fib, rb_thread_t *th) terminated_machine_stack.size = 0; } #endif /* not _WIN32 */ - fib = th->ec.fiber; + fib = th->ec->fiber; if (fib->cont.argc == -1) rb_exc_raise(fib->cont.value); return fib->cont.value; #else /* FIBER_USE_NATIVE */ if (ruby_setjmp(fib->cont.jmpbuf)) { /* restored */ - fib = th->ec.fiber; + fib = th->ec->fiber; if (fib->cont.argc == -1) rb_exc_raise(fib->cont.value); if (next_fib->cont.value == Qundef) { cont_restore_0(&next_fib->cont, &next_fib->cont.value); @@ -1505,7 +1605,7 @@ fiber_switch(rb_fiber_t *fib, int argc, const VALUE *argv, int is_resume) rb_context_t *cont = &fib->cont; rb_thread_t *th = GET_THREAD(); - if (th->ec.fiber == fib) { + if (th->ec->fiber == fib) { /* ignore fiber context switch * because destination fiber is same as current fiber */ @@ -1515,13 +1615,13 @@ fiber_switch(rb_fiber_t *fib, int argc, const VALUE *argv, int is_resume) if (cont_thread_value(cont) != th->self) { rb_raise(rb_eFiberError, "fiber called across threads"); } - else if (cont->saved_ec.protect_tag != th->ec.protect_tag) { + else if (cont->saved_ec.protect_tag != th->ec->protect_tag) { rb_raise(rb_eFiberError, "fiber called across stack rewinding barrier"); } else if (FIBER_TERMINATED_P(fib)) { value = rb_exc_new2(rb_eFiberError, "dead fiber called"); - if (!FIBER_TERMINATED_P(th->ec.fiber)) { + if (!FIBER_TERMINATED_P(th->ec->fiber)) { rb_exc_raise(value); VM_UNREACHABLE(fiber_switch); } @@ -1535,7 +1635,7 @@ fiber_switch(rb_fiber_t *fib, int argc, const VALUE *argv, int is_resume) cont->argc = -1; cont->value = value; #if FIBER_USE_NATIVE - fiber_setcontext(th->root_fiber, th->ec.fiber); + fiber_setcontext(th->root_fiber, th->ec->fiber); #else cont_restore_0(cont, &value); #endif @@ -1567,13 +1667,33 @@ rb_fiber_transfer(VALUE fibval, int argc, const VALUE *argv) return fiber_switch(fib, argc, argv, 0); } +void +rb_fiber_close(rb_fiber_t *fib) +{ + VALUE *vm_stack = fib->cont.saved_ec.vm_stack; + fiber_status_set(fib, FIBER_TERMINATED); + if (fib->cont.type == ROOT_FIBER_CONTEXT) { + rb_thread_recycle_stack_release(vm_stack); + } + else { + ruby_xfree(vm_stack); + } + ec_set_vm_stack(&fib->cont.saved_ec, NULL, 0); + +#if !FIBER_USE_NATIVE + /* should not mark machine stack any more */ + fib->cont.saved_ec.machine.stack_end = NULL; +#endif +} + static void rb_fiber_terminate(rb_fiber_t *fib) { VALUE value = fib->cont.value; VM_ASSERT(FIBER_RESUMED_P(fib)); - fiber_status_set(fib, FIBER_TERMINATED); + rb_fiber_close(fib); + #if FIBER_USE_NATIVE && !defined(_WIN32) /* Ruby must not switch to other thread until storing terminated_machine_stack */ terminated_machine_stack.ptr = fib->ss_sp; @@ -1583,6 +1703,7 @@ rb_fiber_terminate(rb_fiber_t *fib) fib->cont.machine.stack = NULL; fib->cont.machine.stack_size = 0; #endif + fiber_switch(return_fiber(), 1, &value, 0); } @@ -1613,8 +1734,8 @@ rb_fiber_reset_root_local_storage(VALUE thval) { rb_thread_t *th = rb_thread_ptr(thval); - if (th->root_fiber && th->root_fiber != th->ec.fiber) { - th->ec.local_storage = th->root_fiber->cont.saved_ec.local_storage; + if (th->root_fiber && th->root_fiber != th->ec->fiber) { + th->ec->local_storage = th->root_fiber->cont.saved_ec.local_storage; } } @@ -1794,7 +1915,7 @@ Init_Cont(void) #else /* not WIN32 */ pagesize = sysconf(_SC_PAGESIZE); #endif - SET_MACHINE_STACK_END(&th->ec.machine.stack_end); + SET_MACHINE_STACK_END(&th->ec->machine.stack_end); #endif rb_cFiber = rb_define_class("Fiber", rb_cObject); -- cgit v1.2.3