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); }
Object* Thread::locals_remove(STATE, Symbol* key) { if(state->vm() != vm()) { return locals()->remove(state, key); } Fiber* fib = state->vm()->current_fiber.get(); if(fib->nil_p() || fib->root_p()) { return locals()->remove(state, key); } if(fib->locals()->nil_p()) { return cNil; } return fib->locals()->remove(state, key); }
Object* Thread::locals_has_key(STATE, Symbol* key) { /* * If we're not trying to set values on the current thread, * we will set thread locals anyway and not use fiber locals. */ if(state->vm() != vm()) { return locals()->has_key(state, key); } Fiber* fib = state->vm()->current_fiber.get(); if(fib->nil_p() || fib->root_p()) { return locals()->has_key(state, key); } if(try_as<LookupTable>(fib->locals())) { return fib->locals()->has_key(state, key); } return cFalse; }
Array* Thread::locals_keys(STATE) { /* * If we're not trying to set values on the current thread, * we will set thread locals anyway and not use fiber locals. */ if(state->vm() != vm()) { return locals()->all_keys(state); } Fiber* fib = state->vm()->current_fiber.get(); if(fib->nil_p() || fib->root_p()) { return locals()->all_keys(state); } if(try_as<LookupTable>(fib->locals())) { return fib->locals()->all_keys(state); } return Array::create(state, 0); }
Object* Thread::locals_store(STATE, Symbol* key, Object* value) { /* * If we're not trying to set values on the current thread, * we will set thread locals anyway and not use fiber locals. */ if(state->vm() != vm()) { return locals()->store(state, key, value); } Fiber* fib = state->vm()->current_fiber.get(); if(fib->nil_p() || fib->root_p()) { return locals()->store(state, key, value); } if(fib->locals()->nil_p()) { fib->locals(state, LookupTable::create(state)); } return fib->locals()->store(state, key, value); }
bool VM::check_thread_raise_or_kill(STATE) { Exception* exc = interrupted_exception(); if(!exc->nil_p()) { clear_interrupted_exception(); // Only write the locations if there are none. if(exc->locations()->nil_p() || exc->locations()->size() == 0) { exc->locations(this, Location::from_call_stack(state)); } thread_state_.raise_exception(exc); return true; } if(interrupt_by_kill()) { Fiber* fib = current_fiber.get(); if(fib->nil_p() || fib->root_p()) { clear_interrupt_by_kill(); } else { set_check_local_interrupts(); } thread_state_.raise_thread_kill(); return true; } // If the current thread is trying to step, debugger wise, then assist! if(thread_step()) { clear_thread_step(); if(!Helpers::yield_debugger(state, cNil)) return true; } return false; }