Object* Fiber::s_yield(STATE, Arguments& args) { Fiber* fiber = state->vm()->fiber(); OnStack<1> os(state, fiber); { std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex()); if(fiber->root_p()) { Exception::raise_fiber_error(state, "can't yield from root fiber"); } else if(fiber->status() == eTransfer) { Exception::raise_fiber_error(state, "can't yield from transferred fiber"); } fiber->unpack_arguments(state, args); fiber->status(eYielding); } // Being cooperative... fiber->invoke_context()->fiber()->restart(state); // Through the worm hole... fiber->suspend_and_continue(state); // We're back... return fiber->return_value(state); }
Fiber* Fiber::current(STATE) { #ifdef RBX_FIBER_ENABLED Fiber* fib = state->vm()->current_fiber.get(); // Lazily allocate a root fiber. if(fib->nil_p()) { fib = state->memory()->new_object<Fiber>(state, G(fiber)); fib->root(true); fib->status(Fiber::eRunning); fib->data(state->vm()->new_fiber_data(true, fib->stack_size()->to_native())); fib->data()->set_call_frame(state->vm()->call_frame()); state->memory()->native_finalizer(state, fib, (memory::FinalizerFunction)&Fiber::finalize); state->vm()->current_fiber.set(fib); state->vm()->root_fiber.set(fib); } return fib; #else Exception::raise_not_implemented_error(state, "Fibers not supported on this platform"); #endif }
void Fiber::start_on_stack() { #ifdef RBX_FIBER_ENABLED VM* vm = VM::current(); State state_obj(vm), *state = &state_obj; Fiber* fib = Fiber::current(state); // Reset the current fiber again to reset the stack limits so // we can properly detect stack overflows vm->set_current_fiber(fib); Array* result = nil<Array>(); Object* obj = fib->starter()->send(state, G(sym_call), fib->value(), cNil, false); // GC has run! Don't use stack vars! fib = Fiber::current(state); fib->status(Fiber::eDead); fib->dead(cTrue); fib->set_call_frame(state, 0); Fiber* dest = fib->prev(); // If this fiber has already been cleaned up, just ignore this if(!dest->data()) return; assert(!dest->nil_p()); // Box this up so it's in a standard format at the point // of returning, so we can deal with it in the same way // as *args from #yield, #resume, and #transfer if(obj) { result = Array::create(state, 1); result->set(state, 0, obj); } else { if(state->vm()->thread_state()->raise_reason() == cException) { dest->exception(state, state->vm()->thread_state()->current_exception()); } } vm->metrics().system.fibers_destroyed++; dest->run(state); dest->value(state, result); dest->data()->switch_and_orphan(state, fib->data()); // TODO: CallFrame: return from this function rubinius::bug("returning from Fiber::start_on_stack"); #else rubinius::bug("Fibers not supported on this platform"); #endif }
/* This creates the pseudo-Fiber for the Thread. This provides a uniform * means of expressing things like Fiber.current. */ Fiber* Fiber::create(STATE, VM* vm) { Fiber* fiber = state->memory()->new_object_pinned<Fiber>(state, G(fiber)); vm->set_fiber(fiber); vm->set_running(); fiber->vm(vm); fiber->pid(vm->thread()->pid()); fiber->stack_size(vm->thread()->stack_size()); fiber->thread_name(state, String::create(state, vm->name().c_str())); fiber->fiber_id(Fixnum::from(0)); fiber->status(eRunning); fiber->invoke_context(vm); return fiber; }