1 /* GNU LGPL version 2 (or later) - see LICENSE file for details */
8 #include <ccan/ptrint/ptrint.h>
9 #include <ccan/compiler/compiler.h>
10 #include <ccan/build_assert/build_assert.h>
11 #include <ccan/coroutine/coroutine.h>
17 /* Returns lowest stack addres, regardless of growth direction */
18 static UNNEEDED void *coroutine_stack_base(struct coroutine_stack *stack)
20 #if HAVE_STACK_GROWS_UPWARDS
21 return (char *)(stack + 1);
23 return (char *)stack - stack->size;
27 #if HAVE_VALGRIND_MEMCHECK_H
28 #include <valgrind/memcheck.h>
29 static void vg_register_stack(struct coroutine_stack *stack)
31 char *base = coroutine_stack_base(stack);
33 VALGRIND_MAKE_MEM_UNDEFINED(base, stack->size);
34 stack->valgrind_id = VALGRIND_STACK_REGISTER(base,
35 base + stack->size - 1);
38 static void vg_deregister_stack(struct coroutine_stack *stack)
40 VALGRIND_MAKE_MEM_UNDEFINED(coroutine_stack_base(stack), stack->size);
41 VALGRIND_STACK_DEREGISTER(stack->valgrind_id);
43 static bool vg_addressable(void *p, size_t len)
45 return !VALGRIND_CHECK_MEM_IS_ADDRESSABLE(p, len);
48 #define vg_register_stack(stack) do { } while (0)
49 #define vg_deregister_stack(stack) do { } while (0)
50 #define vg_addressable(p, len) (true)
53 struct coroutine_stack *coroutine_stack_init(void *buf, size_t bufsize,
56 struct coroutine_stack *stack;
57 size_t size = bufsize - sizeof(*stack) - metasize;
60 BUILD_ASSERT(COROUTINE_MIN_STKSZ >= MINSIGSTKSZ);
63 if (bufsize < (COROUTINE_MIN_STKSZ + sizeof(*stack) + metasize))
66 #if HAVE_STACK_GROWS_UPWARDS
67 stack = (char *)buf + metasize;
69 stack = (struct coroutine_stack *)
70 ((char *)buf + bufsize - metasize) - 1;
73 stack->magic = COROUTINE_STACK_MAGIC;
75 vg_register_stack(stack);
79 void coroutine_stack_release(struct coroutine_stack *stack, size_t metasize)
81 vg_deregister_stack(stack);
82 memset(stack, 0, sizeof(*stack));
85 struct coroutine_stack *coroutine_stack_check(struct coroutine_stack *stack,
88 if (stack && vg_addressable(stack, sizeof(*stack))
89 && (stack->magic == COROUTINE_STACK_MAGIC)
90 && (stack->size >= COROUTINE_MIN_STKSZ))
95 fprintf(stderr, "%s: NULL coroutine stack\n", abortstr);
98 "%s: Bad coroutine stack at %p (magic=0x%"PRIx64" size=%zd)\n",
99 abortstr, stack, stack->magic, stack->size);
105 size_t coroutine_stack_size(const struct coroutine_stack *stack)
111 static void coroutine_uc_stack(stack_t *uc_stack,
112 const struct coroutine_stack *stack)
114 uc_stack->ss_size = coroutine_stack_size(stack);
115 uc_stack->ss_sp = coroutine_stack_base((struct coroutine_stack *)stack);
117 #endif /* HAVE_UCONTEXT */
120 * Coroutine switching
124 void coroutine_init_(struct coroutine_state *cs,
125 void (*fn)(void *), void *arg,
126 struct coroutine_stack *stack)
128 getcontext (&cs->uc);
130 coroutine_uc_stack(&cs->uc.uc_stack, stack);
132 if (HAVE_POINTER_SAFE_MAKECONTEXT) {
133 makecontext(&cs->uc, (void *)fn, 1, arg);
135 ptrdiff_t si = ptr2int(arg);
136 ptrdiff_t mask = (1UL << (sizeof(int) * 8)) - 1;
138 int hi = si >> (sizeof(int) * 8);
140 makecontext(&cs->uc, (void *)fn, 2, lo, hi);
145 void coroutine_jump(const struct coroutine_state *to)
151 void coroutine_switch(struct coroutine_state *from,
152 const struct coroutine_state *to)
156 rc = swapcontext(&from->uc, &to->uc);
159 #endif /* HAVE_UCONTEXT */