]> git.ozlabs.org Git - ccan/blobdiff - ccan/coroutine/coroutine.c
Fix typos detected by github.com/client9/misspell
[ccan] / ccan / coroutine / coroutine.c
index 60ba41691bc6dbf8e722873ccfa3297c8d9ad4a1..82eb51b656618ea23cb7a6ebd0c077c436eeccad 100644 (file)
@@ -5,6 +5,9 @@
 #include <inttypes.h>
 #include <stdlib.h>
 
+#include <unistd.h>
+#include <sys/mman.h>
+
 #include <ccan/ptrint/ptrint.h>
 #include <ccan/compiler/compiler.h>
 #include <ccan/build_assert/build_assert.h>
  * 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 <valgrind/memcheck.h>
+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;