diff options
-rw-r--r-- | src/pulp.c | 21 |
1 files changed, 15 insertions, 6 deletions
@@ -290,16 +290,23 @@ static void destroy_context(pulp_context_t *context) * * Note that though this is coded as an infinite loop, pulp_schedule()'s * default target is pulp->caller_context. When the run queue is drained, the - * caller context is entered, and pulp_tick() returns. + * caller context is swapped with the trampoline, and pulp_tick() returns. */ static void trampoline(pulp_t *pulp) { assert(pulp); + /* note any time the trampoline is entered with a non-NULL + * pulp->current, it's assumed to be an exited fiber situation @ + * pulp->current. So anything swapping to trampoline_context outside + * of the fiber cleanup path must either set pulp->current to NULL or + * be a fiber return/destroy path. + */ for (;;) { if (pulp->current) { destroy_context(&pulp->current->context); put_current_fiber(pulp, &pulp->fibers.free); + pulp->current = NULL; } pulp_schedule(pulp); @@ -383,6 +390,7 @@ static void expire_alarms(pulp_t *pulp) static void pulp_schedule(pulp_t *pulp) { pulp_context_t *target_context = &pulp->caller_context; + pulp_context_t *source_context = &pulp->trampoline_context; pulp_fiber_t *current; assert(pulp); @@ -390,15 +398,15 @@ static void pulp_schedule(pulp_t *pulp) current = pulp->current; pulp->current = NULL; - if (!list_empty(&pulp->fibers.run)) { + if (!list_empty(&pulp->fibers.run) && !pulp->exited) { set_current_fiber(pulp, &pulp->fibers.run); target_context = &pulp->current->context; } if (current) - swap_context(¤t->context, target_context); - else - enter_context(target_context); + source_context = ¤t->context; + + swap_context(source_context, target_context); } @@ -497,9 +505,10 @@ void pulp_run(pulp_t *pulp) void pulp_exit(pulp_t *pulp) { assert(pulp); + assert(pulp->current); pulp->exited = 1; - enter_context(&pulp->caller_context); + swap_context(&pulp->current->context, &pulp->trampoline_context); } |