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); }
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; }
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; }
void test_new(void) { stacklet_handle h = stacklet_new(thrd, empty_callback, (void *)123); assert(h == EMPTY_STACKLET_HANDLE); }
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; }