Ejemplo n.º 1
0
  void Fiber::start_on_stack() {
#ifdef FIBER_ENABLED
    VM* state = VM::current();

    Fiber* fib = Fiber::current(state);

    // Affix this fiber to this thread now.
    fib->state_ = state;

    fib->starter()->send(state, NULL, G(sym_call));
    // GC has run! Don't use stack vars!

    fib = Fiber::current(state);
    fib->status_ = Fiber::eDead;

    Fiber* dest = fib->prev();
    assert(!dest->nil_p());

    dest->run();
    dest->value(state, Qnil);
    state->set_current_fiber(dest);

    if(setcontext(dest->ucontext()) != 0)
      assert(0 && "fatal swapcontext() error");

    assert(0 && "fatal start_on_stack error");
#else
    abort();
#endif
  }
Ejemplo n.º 2
0
  Object* Fiber::resume(STATE, Arguments& args, CallFrame* calling_environment) {
#ifdef FIBER_ENABLED
    if(!prev_->nil_p() || root_) return Primitives::failure();

    Object* val = Qnil;
    if(args.total() == 1) {
      val = args.get_argument(0);
    } else if(args.total() > 1) {
      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);
    return cur->value();
#else
    return Primitives::failure();
#endif
  }
Ejemplo n.º 3
0
  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
  }
Ejemplo n.º 4
0
  void Fiber::start_on_stack() {
#ifdef FIBER_ENABLED
    VM* state = VM::current();

    Fiber* fib = Fiber::current(state);

    // Affix this fiber to this thread now.
    fib->state_ = state;

    Array* result = (Array*)Qnil;
    Object* obj = fib->starter()->send(state, NULL, G(sym_call), fib->value(), Qnil, false);
    // GC has run! Don't use stack vars!

    fib = Fiber::current(state);
    fib->status_ = Fiber::eDead;
    fib->set_ivar(state, state->symbol("@dead"), Qtrue);

    Fiber* dest = fib->prev();
    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->thread_state()->raise_reason() == cException) {
        dest->exception(state, state->thread_state()->current_exception());
      }
    }

    dest->run();
    dest->value(state, result);
    state->set_current_fiber(dest);

    if(setcontext(dest->ucontext()) != 0)
      assert(0 && "fatal swapcontext() error");

    assert(0 && "fatal start_on_stack error");
#else
    abort();
#endif
  }
Ejemplo n.º 5
0
  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
  }
Ejemplo n.º 6
0
  Fiber* Fiber::create(STATE, Integer* i_stack_size, Object* callable) {
#ifdef FIBER_ENABLED
    int stack_size = i_stack_size->to_native();

    if(stack_size < 64 * 1024) {
      stack_size = 64 * 1024;
    }

    Fiber* fib = state->new_object<Fiber>(G(fiber));
    fib->starter(state, callable);
    fib->prev_ = (Fiber*)Qnil;
    fib->top_ = 0;
    fib->root_ = false;
    fib->state_ = 0;
    fib->status_ = Fiber::eSleeping;
    fib->stack_size_ = stack_size;
    fib->stack_ = malloc(stack_size);
    fib->context_ = new ucontext_t;

    state->om->needs_finalization(fib, (FinalizerFunction)&Fiber::finalize);

    ucontext_t* ctx = fib->ucontext();

    if(getcontext(ctx) != 0) assert(0 && "fatal getcontext() error");

    ctx->uc_link = 0;
    ctx->uc_stack.ss_sp = (char *) fib->stack_;
    ctx->uc_stack.ss_size = stack_size;
    ctx->uc_stack.ss_flags = 0;

    makecontext(ctx, start_on_stack, 0);

    return fib;
#else
    return reinterpret_cast<Fiber*>(Primitives::failure());
#endif
  }