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 }
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 }