Esempio n. 1
0
  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);
  }
Esempio n. 2
0
  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
  }
Esempio n. 3
0
  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
  }
Esempio n. 4
0
  /* 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;
  }