int mill_suspend(void) { /* Even if process never gets idle, we have to process external events once in a while. The external signal may very well be a deadline or a user-issued command that cancels the CPU intensive operation. */ static int counter = 0; if(counter >= 103) { mill_wait(0); counter = 0; } /* Store the context of the current coroutine, if any. */ if(mill_running && sigsetjmp(mill_running->ctx, 0)) return mill_running->result; while(1) { /* If there's a coroutine ready to be executed go for it. */ if(!mill_slist_empty(&mill_ready)) { ++counter; struct mill_slist_item *it = mill_slist_pop(&mill_ready); mill_running = mill_cont(it, struct mill_cr, ready); siglongjmp(mill_running->ctx, 1); } /* Otherwise, we are going to wait for sleeping coroutines and for external events. */ mill_wait(1); mill_assert(!mill_slist_empty(&mill_ready)); counter = 0; }
void *mill_allocstack(void) { if(!mill_slist_empty(&mill_cached_stacks)) { --mill_num_cached_stacks; return (void*)(mill_slist_pop(&mill_cached_stacks) + 1); } char *ptr = malloc(MILL_STACK_SIZE); assert(ptr); return ptr + MILL_STACK_SIZE; }
void *mill_allocstack(void) { if(!mill_slist_empty(&mill_cached_stacks)) { --mill_num_cached_stacks; return (void*)(mill_slist_pop(&mill_cached_stacks) + 1); } void *ptr = mill_allocstackmem(); if(!ptr) mill_panic("not enough memory to allocate coroutine stack"); return ptr; }