X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fcoroutine%2Fcoroutine.c;h=82eb51b656618ea23cb7a6ebd0c077c436eeccad;hb=d1a951b82386391b82e48b32403891f85e253565;hp=60ba41691bc6dbf8e722873ccfa3297c8d9ad4a1;hpb=1ddc881f084e2527ad9e3541807469920ac299b4;p=ccan diff --git a/ccan/coroutine/coroutine.c b/ccan/coroutine/coroutine.c index 60ba4169..82eb51b6 100644 --- a/ccan/coroutine/coroutine.c +++ b/ccan/coroutine/coroutine.c @@ -5,6 +5,9 @@ #include #include +#include +#include + #include #include #include @@ -14,12 +17,7 @@ * Stack management */ -struct coroutine_stack { - uint64_t magic; - size_t size; -}; - -/* 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 @@ -29,12 +27,38 @@ static UNNEEDED void *coroutine_stack_base(struct coroutine_stack *stack) #endif } +#if HAVE_VALGRIND_MEMCHECK_H +#include +static void vg_register_stack(struct coroutine_stack *stack) +{ + char *base = coroutine_stack_base(stack); + + VALGRIND_MAKE_MEM_UNDEFINED(base, stack->size); + stack->valgrind_id = VALGRIND_STACK_REGISTER(base, + base + stack->size - 1); +} + +static void vg_deregister_stack(struct coroutine_stack *stack) +{ + VALGRIND_MAKE_MEM_UNDEFINED(coroutine_stack_base(stack), stack->size); + VALGRIND_STACK_DEREGISTER(stack->valgrind_id); +} +static bool vg_addressable(void *p, size_t len) +{ + return !VALGRIND_CHECK_MEM_IS_ADDRESSABLE(p, len); +} +#else +#define vg_register_stack(stack) do { } while (0) +#define vg_deregister_stack(stack) do { } while (0) +#define vg_addressable(p, len) (true) +#endif + struct coroutine_stack *coroutine_stack_init(void *buf, size_t bufsize, size_t metasize) { struct coroutine_stack *stack; + size_t size = bufsize - sizeof(*stack) - metasize; - BUILD_ASSERT(COROUTINE_STK_OVERHEAD == sizeof(*stack)); #ifdef MINSIGSTKSZ BUILD_ASSERT(COROUTINE_MIN_STKSZ >= MINSIGSTKSZ); #endif @@ -49,21 +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->size = bufsize - sizeof(*stack) - metasize; + 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) { - memset(stack, 0, sizeof(*stack)); + vg_deregister_stack(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 && (stack->magic == COROUTINE_STACK_MAGIC) + if (stack && vg_addressable(stack, sizeof(*stack)) + && ((stack->magic == COROUTINE_STACK_MAGIC_BUF) + || (stack->magic == COROUTINE_STACK_MAGIC_ALLOC)) && (stack->size >= COROUTINE_MIN_STKSZ)) return stack;