void dill_ctx_stack_term(struct dill_ctx_stack *ctx) { /* Deallocate leftover coroutines. */ struct dill_qlist *it; while((it = dill_qlist_pop(&ctx->cache)) != &ctx->cache) { #if (HAVE_POSIX_MEMALIGN && HAVE_MPROTECT) & !defined DILL_NOGUARD void *ptr = ((uint8_t*)(it + 1)) - dill_stack_size - dill_page_size(); int rc = mprotect(ptr, dill_page_size(), PROT_READ|PROT_WRITE); dill_assert(rc == 0); free(ptr); #else void *ptr = ((uint8_t*)(it + 1)) - dill_stack_size; free(ptr); #endif } }
void *dill_allocstack(size_t *stack_size) { struct dill_ctx_stack *ctx = &dill_getctx->stack; if(stack_size) *stack_size = dill_stack_size; /* If there's a cached stack, use it. */ if(!dill_qlist_empty(&ctx->cache)) { --ctx->count; return (void*)(dill_qlist_pop(&ctx->cache) + 1); } /* Allocate a new stack. */ uint8_t *top; #if (HAVE_POSIX_MEMALIGN && HAVE_MPROTECT) & !defined DILL_NOGUARD /* Allocate the stack so that it's memory-page-aligned. Add one page as stack overflow guard. */ size_t sz = dill_align(dill_stack_size, dill_page_size()) + dill_page_size(); uint8_t *ptr; int rc = posix_memalign((void**)&ptr, dill_page_size(), sz); if(dill_slow(rc != 0)) { errno = rc; return NULL; } /* The bottom page is used as a stack guard. This way stack overflow will cause segfault rather than randomly overwrite the heap. */ rc = mprotect(ptr, dill_page_size(), PROT_NONE); if(dill_slow(rc != 0)) { int err = errno; free(ptr); errno = err; return NULL; } top = ptr + dill_page_size() + dill_stack_size; #else /* Simple allocation without a guard page. */ uint8_t *ptr = malloc(dill_stack_size); if(dill_slow(!ptr)) { errno = ENOMEM; return NULL; } top = ptr + dill_stack_size; #endif return top; }
break; dill_trigger(&tmcl->cl, ETIMEDOUT); fired = 1; } } /* Never retry the poll when in non-blocking mode. */ if(!block || fired) break; /* If the timeout was hit but there were no expired timers, do the poll again. It can happen if the timers were canceled in the meantime. */ } ctx->last_poll = nw; } /* There's a coroutine ready to be executed so jump to it. */ struct dill_slist *it = dill_qlist_pop(&ctx->ready); it->next = NULL; ctx->r = dill_cont(it, struct dill_cr, ready); /* dill_longjmp has to be at the end of a function body, otherwise stack unwinding information will be trimmed if a crash occurs in this function. */ dill_longjmp(ctx->r->ctx); return 0; } static void dill_docancel(struct dill_cr *cr, int id, int err) { /* Sanity check: Make sure that the coroutine was really suspended. */ dill_assert(!cr->ready.next); /* Remove the clauses from endpoints' lists of waiting coroutines. */ struct dill_slist *it; for(it = dill_slist_next(&cr->clauses); it != &cr->clauses;