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_slist_empty(&ctx->cache)) { --ctx->count; return (void*)(dill_slist_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 a 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 a stack overflow will cause a segfault instead of randomly overwriting 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; }
/* The final part of go(). Gets called when the coroutine is finished. */ void dill_epilogue(void) { struct dill_ctx_cr *ctx = &dill_getctx->cr; /* Mark the coroutine as finished. */ ctx->r->done = 1; /* If there's a coroutine waiting for us to finish, unblock it now. */ if(ctx->r->closer) dill_cancel(ctx->r->closer, 0); /* Deallocate the coroutine, unless, of course, it is already in the process of being closed. */ if(!ctx->r->no_blocking1) { /* If this is the last coroutine in the bundle and there's someone waiting for hdone() on the bundle unblock them. */ if(dill_list_oneitem(&ctx->r->bundle)) { struct dill_bundle *b = dill_cont(ctx->r->bundle.next, struct dill_bundle, crs); if(b->waiter) dill_trigger(b->waiter, 0); } dill_list_erase(&ctx->r->bundle); dill_cr_close(&ctx->r->vfs); } /* With no clauses added, this call will never return. */ dill_assert(dill_slist_empty(&ctx->r->clauses)); dill_wait(); }