#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
*/
-/* 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
((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;