X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fcoroutine%2Fcoroutine.c;h=82eb51b656618ea23cb7a6ebd0c077c436eeccad;hb=d1a951b82386391b82e48b32403891f85e253565;hp=fa321ab85a6cf55a2fccb3113cc222352b26bc8d;hpb=fe3995b4e626466ab211e37392f8500f1fffb5c7;p=ccan diff --git a/ccan/coroutine/coroutine.c b/ccan/coroutine/coroutine.c index fa321ab8..82eb51b6 100644 --- a/ccan/coroutine/coroutine.c +++ b/ccan/coroutine/coroutine.c @@ -5,6 +5,9 @@ #include #include +#include +#include + #include #include #include @@ -14,7 +17,7 @@ * Stack management */ -/* Returns lowest stack addres, regardless of growth direction */ +/* Returns lowest stack address, regardless of growth direction */ static UNNEEDED void *coroutine_stack_base(struct coroutine_stack *stack) { #if HAVE_STACK_GROWS_UPWARDS @@ -70,23 +73,90 @@ struct coroutine_stack *coroutine_stack_init(void *buf, size_t bufsize, ((char *)buf + bufsize - metasize) - 1; #endif - stack->magic = COROUTINE_STACK_MAGIC; + stack->magic = COROUTINE_STACK_MAGIC_BUF; stack->size = size; vg_register_stack(stack); return stack; } +struct coroutine_stack *coroutine_stack_alloc(size_t totalsize, size_t metasize) +{ + struct coroutine_stack *stack; + size_t pgsz = getpagesize(); + size_t mapsize; + char *map, *guard; + int rc; + + mapsize = ((totalsize + (pgsz - 1)) & ~(pgsz - 1)) + pgsz; + + map = mmap(NULL, mapsize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map == MAP_FAILED) + return NULL; + +#if HAVE_STACK_GROWS_UPWARDS + guard = map + mapsize - pgsz; + stack = (struct coroutine_stack *)(guard - totalsize + metasize); +#else + guard = map; + stack = (struct coroutine_stack *)(map + pgsz + totalsize - metasize) + - 1; +#endif + + rc = mprotect(guard, pgsz, PROT_NONE); + if (rc != 0) { + munmap(map, mapsize); + return NULL; + } + + stack->magic = COROUTINE_STACK_MAGIC_ALLOC; + stack->size = totalsize - sizeof(*stack) - metasize; + + vg_register_stack(stack); + + return stack; +} + +static void coroutine_stack_free(struct coroutine_stack *stack, size_t metasize) +{ + void *map; + size_t pgsz = getpagesize(); + size_t totalsize = stack->size + sizeof(*stack) + metasize; + size_t mapsize = ((totalsize + (pgsz - 1)) & ~(pgsz - 1)) + pgsz; + +#if HAVE_STACK_GROWS_UPWARDS + map = (char *)(stack + 1) + stack->size + pgsz - mapsize; +#else + map = (char *)stack - stack->size - pgsz; +#endif + + munmap(map, mapsize); +} + void coroutine_stack_release(struct coroutine_stack *stack, size_t metasize) { vg_deregister_stack(stack); - memset(stack, 0, sizeof(*stack)); + + switch (stack->magic) { + case COROUTINE_STACK_MAGIC_BUF: + memset(stack, 0, sizeof(*stack)); + break; + + case COROUTINE_STACK_MAGIC_ALLOC: + coroutine_stack_free(stack, metasize); + break; + + default: + abort(); + } } struct coroutine_stack *coroutine_stack_check(struct coroutine_stack *stack, const char *abortstr) { if (stack && vg_addressable(stack, sizeof(*stack)) - && (stack->magic == COROUTINE_STACK_MAGIC) + && ((stack->magic == COROUTINE_STACK_MAGIC_BUF) + || (stack->magic == COROUTINE_STACK_MAGIC_ALLOC)) && (stack->size >= COROUTINE_MIN_STKSZ)) return stack;