Example #1
0
void test_simple_switch(void)
{
  status = 0;
  stacklet_handle h = stacklet_new(thrd, switchbackonce_callback, (void *)123);
  assert(h != EMPTY_STACKLET_HANDLE);
  assert(status == 1);
  status = 2;
  h = stacklet_switch(thrd, h);
  assert(status == 3);
  assert(h == EMPTY_STACKLET_HANDLE);
}
Example #2
0
static PyObject *
do_switch(Fiber *self, PyObject *value)
{
    PyThreadState *tstate;
    stacklet_handle stacklet_h;
    Fiber *current;
    PyObject *result;

    /* save state */
    current = _global_state.current;
    tstate = PyThreadState_Get();
    current->ts.recursion_depth = tstate->recursion_depth;
    current->ts.frame = tstate->frame;
    current->ts.exc_type = tstate->exc_type;
    current->ts.exc_value = tstate->exc_value;
    current->ts.exc_traceback = tstate->exc_traceback;

    _global_state.origin = current;
    _global_state.destination = self;
    _global_state.value = value;

    if (self->stacklet_h == NULL) {
        stacklet_h = stacklet_new(self->thread_h, stacklet__callback, NULL);
    } else {
        stacklet_h = stacklet_switch(self->stacklet_h);
    }

    result = stacklet__post_switch(stacklet_h);

    /* restore state */
    tstate = PyThreadState_Get();
    tstate->recursion_depth = current->ts.recursion_depth;
    tstate->frame = current->ts.frame;
    tstate->exc_type = current->ts.exc_type;
    tstate->exc_value = current->ts.exc_value;
    tstate->exc_traceback = current->ts.exc_traceback;
    current->ts.frame = NULL;
    current->ts.exc_type = NULL;
    current->ts.exc_value = NULL;
    current->ts.exc_traceback = NULL;

    return result;
}
Example #3
0
static PyObject *
do_switch(Fiber *self, PyObject *value)
{
    PyThreadState *tstate;
    stacklet_handle stacklet_h;
    Fiber *origin, *current;
    PyObject *result;

    /* save state */
    current = get_current();
    ASSERT(current != NULL);
    tstate = PyThreadState_Get();
    ASSERT(tstate != NULL);
    ASSERT(tstate->dict != NULL);
    current->ts.recursion_depth = tstate->recursion_depth;
    current->ts.frame = tstate->frame;
    current->ts.exc_type = tstate->exc_type;
    current->ts.exc_value = tstate->exc_value;
    current->ts.exc_traceback = tstate->exc_traceback;
    ASSERT(current->stacklet_h == NULL);

    /* _global_state is to pass values across a switch. Its contents are only
     * valid immediately before and after a switch. For any other purpose, the
     * current fiber is identified by current_fiber_key in the thread state
     * dictionary. */
    _global_state.origin = current;
    _global_state.value = value;

    /* make the target fiber the new current one. */
    if (PyDict_SetItem(tstate->dict, current_fiber_key, (PyObject *) self) < 0) {
        return NULL;
    }

    /* switch to existing, or create new fiber */
    if (self->stacklet_h == NULL) {
        stacklet_h = stacklet_new(self->thread_h, stacklet__callback, NULL);
    } else {
        stacklet_h = stacklet_switch(self->stacklet_h);
    }

    /* need to store the handle of the stacklet that switched to us, so that
     * later it can be resumed again. (stacklet_h can also be
     * EMPTY_STACKLET_HANDLE in which case the stacklet exited) */
    ASSERT(stacklet_h != NULL);
    origin = _global_state.origin;
    origin->stacklet_h = stacklet_h;
    current->stacklet_h = NULL;  /* handle is valid only once */
    result = _global_state.value;

    /* back to the fiber that did the switch. this may drop the refcount on
     * origin to zero. */
    if (PyDict_SetItem(tstate->dict, current_fiber_key, (PyObject *) current) < 0) {
        return NULL;
    }

    /* restore state */
    tstate->recursion_depth = current->ts.recursion_depth;
    tstate->frame = current->ts.frame;
    tstate->exc_type = current->ts.exc_type;
    tstate->exc_value = current->ts.exc_value;
    tstate->exc_traceback = current->ts.exc_traceback;
    current->ts.frame = NULL;
    current->ts.exc_type = NULL;
    current->ts.exc_value = NULL;
    current->ts.exc_traceback = NULL;

    return result;
}
Example #4
0
void test_new(void)
{
  stacklet_handle h = stacklet_new(thrd, empty_callback, (void *)123);
  assert(h == EMPTY_STACKLET_HANDLE);
}
Example #5
0
int withdepth(int self, float d)
{
  int res = 0;
  if (d > 0.0)
    {
      foo_t *foo = malloc(sizeof(foo_t));
      foo_t *foo2 = malloc(sizeof(foo_t));
      foo->self = self;
      foo->d = d;
      foo->next = foo2;
      foo2->self = self + 100;
      foo2->d = d;
      foo2->next = NULL;
      res = withdepth(self, d - 1.1);
      assert(foo->self == self);
      assert(foo->d    == d);
      assert(foo->next == foo2);
      assert(foo2->self == self + 100);
      assert(foo2->d    == d);
      assert(foo2->next == NULL);
      free(foo2);
      free(foo);
    }
  else
    {
      stacklet_handle h;
      int n = rand() % 10;
      if (n == self || (status >= statusmax && handles[n] == NULL))
        return 1;

      //printf("status == %d, self = %d\n", status, self);
      assert(handles[self] == NULL);
      assert(nextstep == -1);
      nextstep = ++status;
      comefrom = self;
      gointo = n;
      if (handles[n] == NULL)
        {
          /* start a new stacklet */
          //printf("new %d\n", n);
          h = stacklet_new(thrd, variousdepths_callback, (void *)(ptrdiff_t)n);
        }
      else
        {
          /* switch to this stacklet */
          //printf("switch to %d\n", n);
          h = handles[n];
          handles[n] = NULL;
          h = stacklet_switch(thrd, h);
        }
      //printf("back in self = %d, coming from %d\n", self, comefrom);
      assert(nextstep == status);
      nextstep = -1;
      assert(gointo == self);
      assert(comefrom != self);
      assert(handles[self] == NULL);
      if (comefrom != -42)
        {
          assert(0 <= comefrom && comefrom < 10);
          assert(handles[comefrom] == NULL);
          handles[comefrom] = h;
        }
      else
        assert(h == EMPTY_STACKLET_HANDLE);
      comefrom = -1;
      gointo = -1;
    }
  assert((res & (res-1)) == 0);   /* to prevent a tail-call to withdepth() */
  return res;
}