aboutsummaryrefslogtreecommitdiffstats
path: root/cont.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-26 08:32:49 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-26 08:32:49 +0000
commitfbf899e0204808fa2a01ade8ca8b69feb1bcc479 (patch)
tree7ccbb6b6733ccb07c28b7df28e3e2a6b604cc731 /cont.c
parentf8f36a133c610b9ec6aa1f45ffcfc1e74b5e473f (diff)
downloadruby-fbf899e0204808fa2a01ade8ca8b69feb1bcc479.tar.gz
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
Diffstat (limited to 'cont.c')
-rw-r--r--cont.c375
1 files changed, 248 insertions, 127 deletions
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;
@@ -190,14 +190,61 @@ fiber_status_name(enum fiber_status s)
}
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);