Object* Fiber::resume(STATE, Arguments& args, CallFrame* calling_environment) { #ifdef RBX_FIBER_ENABLED if(!data_) { data_ = state->vm()->new_fiber_data(); } if(status_ == Fiber::eDead || data_->dead_p()) { Exception::fiber_error(state, "dead fiber called"); } if(!prev_->nil_p()) { Exception::fiber_error(state, "double resume"); } if(data_->thread() && data_->thread() != state->vm()) { Exception::fiber_error(state, "cross thread fiber resuming is illegal"); } Array* val = args.as_array(state); value(state, val); Fiber* cur = Fiber::current(state); prev(state, cur); cur->sleep(calling_environment); run(); state->vm()->set_current_fiber(this); data_->switch_to(state, cur->data_); // Back here when someone yields back to us! // Beware here, because the GC has probably run so GC pointers on the C++ stack // can't be accessed. cur = Fiber::current(state); state->set_call_frame(cur->call_frame()); if(!cur->exception()->nil_p()) { state->raise_exception(cur->exception()); cur->exception(state, nil<Exception>()); return 0; } Array* ret = cur->value(); if(ret->nil_p()) return cNil; switch(ret->size()) { case 0: return cNil; case 1: return ret->get(state, 0); default: return ret; } #else return Primitives::failure(); #endif }
Object* Fiber::transfer(STATE, Arguments& args) { #ifdef RBX_FIBER_ENABLED if(!data()) { data(state->vm()->new_fiber_data(stack_size()->to_native())); } if(status() == Fiber::eDead || data()->dead_p()) { Exception::raise_fiber_error(state, "dead fiber called"); } if(data()->thread() && data()->thread() != state->vm()) { Exception::raise_fiber_error(state, "cross thread fiber resuming is illegal"); } Array* val = args.as_array(state); value(state, val); Fiber* cur = Fiber::current(state); Fiber* root = state->vm()->root_fiber.get(); assert(root); prev(state, root); cur->sleep(state); run(state); data()->switch_to(state, cur->data()); // Back here when someone transfers back to us! // Beware here, because the GC has probably run so GC pointers on the C++ stack // can't be accessed. cur = Fiber::current(state); if(!cur->exception()->nil_p()) { state->raise_exception(cur->exception()); cur->exception(state, nil<Exception>()); return 0; } Array* ret = cur->value(); if(ret->nil_p()) return cNil; switch(ret->size()) { case 0: return cNil; case 1: return ret->get(state, 0); default: return ret; } #else Exception::raise_not_implemented_error(state, "Fibers not supported on this platform"); #endif }
Object* Fiber::resume(STATE, Arguments& args, CallFrame* calling_environment) { #ifdef FIBER_ENABLED if(status_ == Fiber::eDead) { Exception::fiber_error(state, "dead fiber called"); } if(!prev_->nil_p()) { Exception::fiber_error(state, "double resume"); } Array* val = args.as_array(state); value(state, val); Fiber* cur = Fiber::current(state); prev(state, cur); cur->sleep(calling_environment); run(); state->set_current_fiber(this); if(swapcontext(cur->ucontext(), context_) != 0) assert(0 && "fatal swapcontext() error"); // Back here when someone yields back to us! // Beware here, because the GC has probably run so GC pointers on the C++ stack // can't be accessed. cur = Fiber::current(state); if(!cur->exception()->nil_p()) { state->thread_state()->raise_exception(cur->exception()); cur->exception(state, (Exception*)Qnil); return 0; } Array* ret = cur->value(); if(ret->nil_p()) return Qnil; switch(ret->size()) { case 0: return Qnil; case 1: return ret->get(state, 0); default: return ret; } #else return Primitives::failure(); #endif }
Object* Fiber::s_yield(STATE, Arguments& args, CallFrame* calling_environment) { #ifdef FIBER_ENABLED Fiber* cur = Fiber::current(state); Fiber* dest_fib = cur->prev(); assert(cur != dest_fib); if(cur->root_) { Exception::fiber_error(state, "can't yield from root fiber"); } cur->prev(state, (Fiber*)Qnil); Array* val = args.as_array(state); dest_fib->value(state, val); cur->sleep(calling_environment); dest_fib->run(); state->set_current_fiber(dest_fib); if(swapcontext(cur->ucontext(), dest_fib->ucontext()) != 0) assert(0 && "fatal swapcontext() error"); // Back here when someone yields back to us! // Beware here, because the GC has probably run so GC pointers on the C++ stack // can't be accessed. cur = Fiber::current(state); Array* ret = cur->value(); if(ret->nil_p()) return Qnil; switch(ret->size()) { case 0: return Qnil; case 1: return ret->get(state, 0); default: return ret; } #else return Primitives::failure(); #endif }
Object* Fiber::s_yield(STATE, Arguments& args) { #ifdef RBX_FIBER_ENABLED Fiber* cur = Fiber::current(state); Fiber* dest_fib = cur->prev(); assert(cur != dest_fib); if(cur->root()) { Exception::raise_fiber_error(state, "can't yield from root fiber"); } cur->prev(state, nil<Fiber>()); Array* val = args.as_array(state); dest_fib->value(state, val); cur->sleep(state); dest_fib->run(state); dest_fib->data()->switch_to(state, cur->data()); // Back here when someone yields back to us! // Beware here, because the GC has probably run so GC pointers on the C++ stack // can't be accessed. cur = Fiber::current(state); Array* ret = cur->value(); if(ret->nil_p()) return cNil; switch(ret->size()) { case 0: return cNil; case 1: return ret->get(state, 0); default: return ret; } #else Exception::raise_not_implemented_error(state, "Fibers not supported on this platform"); #endif }
Object* Fiber::s_yield(STATE, Arguments& args, CallFrame* calling_environment) { #ifdef FIBER_ENABLED Fiber* cur = Fiber::current(state); Fiber* dest_fib = cur->prev(); assert(cur != dest_fib); cur->prev(state, (Fiber*)Qnil); Object* val = Qnil; if(args.total() == 1) { val = args.get_argument(0); } else if(args.total() > 1) { val = args.as_array(state); } dest_fib->value(state, val); cur->sleep(calling_environment); dest_fib->run(); state->set_current_fiber(dest_fib); if(swapcontext(cur->ucontext(), dest_fib->ucontext()) != 0) assert(0 && "fatal swapcontext() error"); // Back here when someone yields back to us! // Beware here, because the GC has probably run so GC pointers on the C++ stack // can't be accessed. cur = Fiber::current(state); return cur->value(); #else return Primitives::failure(); #endif }