1 /* GNU LGPL version 2 (or later) - see LICENSE file for details */
11 #include <ccan/ptrint/ptrint.h>
12 #include <ccan/compiler/compiler.h>
13 #include <ccan/build_assert/build_assert.h>
14 #include <ccan/coroutine/coroutine.h>
20 /* Returns lowest stack addres, regardless of growth direction */
21 static UNNEEDED void *coroutine_stack_base(struct coroutine_stack *stack)
23 #if HAVE_STACK_GROWS_UPWARDS
24 return (char *)(stack + 1);
26 return (char *)stack - stack->size;
30 #if HAVE_VALGRIND_MEMCHECK_H
31 #include <valgrind/memcheck.h>
32 static void vg_register_stack(struct coroutine_stack *stack)
34 char *base = coroutine_stack_base(stack);
36 VALGRIND_MAKE_MEM_UNDEFINED(base, stack->size);
37 stack->valgrind_id = VALGRIND_STACK_REGISTER(base,
38 base + stack->size - 1);
41 static void vg_deregister_stack(struct coroutine_stack *stack)
43 VALGRIND_MAKE_MEM_UNDEFINED(coroutine_stack_base(stack), stack->size);
44 VALGRIND_STACK_DEREGISTER(stack->valgrind_id);
46 static bool vg_addressable(void *p, size_t len)
48 return !VALGRIND_CHECK_MEM_IS_ADDRESSABLE(p, len);
51 #define vg_register_stack(stack) do { } while (0)
52 #define vg_deregister_stack(stack) do { } while (0)
53 #define vg_addressable(p, len) (true)
56 struct coroutine_stack *coroutine_stack_init(void *buf, size_t bufsize,
59 struct coroutine_stack *stack;
60 size_t size = bufsize - sizeof(*stack) - metasize;
63 BUILD_ASSERT(COROUTINE_MIN_STKSZ >= MINSIGSTKSZ);
66 if (bufsize < (COROUTINE_MIN_STKSZ + sizeof(*stack) + metasize))
69 #if HAVE_STACK_GROWS_UPWARDS
70 stack = (char *)buf + metasize;
72 stack = (struct coroutine_stack *)
73 ((char *)buf + bufsize - metasize) - 1;
76 stack->magic = COROUTINE_STACK_MAGIC_BUF;
78 vg_register_stack(stack);
82 struct coroutine_stack *coroutine_stack_alloc(size_t totalsize, size_t metasize)
84 struct coroutine_stack *stack;
85 size_t pgsz = getpagesize();
90 mapsize = ((totalsize + (pgsz - 1)) & ~(pgsz - 1)) + pgsz;
92 map = mmap(NULL, mapsize, PROT_READ | PROT_WRITE,
93 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
94 if (map == MAP_FAILED)
97 #if HAVE_STACK_GROWS_UPWARDS
98 guard = map + mapsize - pgsz;
99 stack = (struct coroutine_stack *)(guard - totalsize + metasize);
102 stack = (struct coroutine_stack *)(map + pgsz + totalsize - metasize)
106 rc = mprotect(guard, pgsz, PROT_NONE);
108 munmap(map, mapsize);
112 stack->magic = COROUTINE_STACK_MAGIC_ALLOC;
113 stack->size = totalsize - sizeof(*stack) - metasize;
115 vg_register_stack(stack);
120 static void coroutine_stack_free(struct coroutine_stack *stack, size_t metasize)
123 size_t pgsz = getpagesize();
124 size_t totalsize = stack->size + sizeof(*stack) + metasize;
125 size_t mapsize = ((totalsize + (pgsz - 1)) & ~(pgsz - 1)) + pgsz;
127 #if HAVE_STACK_GROWS_UPWARDS
128 map = (char *)(stack + 1) + stack->size + pgsz - mapsize;
130 map = (char *)stack - stack->size - pgsz;
133 munmap(map, mapsize);
136 void coroutine_stack_release(struct coroutine_stack *stack, size_t metasize)
138 vg_deregister_stack(stack);
140 switch (stack->magic) {
141 case COROUTINE_STACK_MAGIC_BUF:
142 memset(stack, 0, sizeof(*stack));
145 case COROUTINE_STACK_MAGIC_ALLOC:
146 coroutine_stack_free(stack, metasize);
154 struct coroutine_stack *coroutine_stack_check(struct coroutine_stack *stack,
155 const char *abortstr)
157 if (stack && vg_addressable(stack, sizeof(*stack))
158 && ((stack->magic == COROUTINE_STACK_MAGIC_BUF)
159 || (stack->magic == COROUTINE_STACK_MAGIC_ALLOC))
160 && (stack->size >= COROUTINE_MIN_STKSZ))
165 fprintf(stderr, "%s: NULL coroutine stack\n", abortstr);
168 "%s: Bad coroutine stack at %p (magic=0x%"PRIx64" size=%zd)\n",
169 abortstr, stack, stack->magic, stack->size);
175 size_t coroutine_stack_size(const struct coroutine_stack *stack)
181 static void coroutine_uc_stack(stack_t *uc_stack,
182 const struct coroutine_stack *stack)
184 uc_stack->ss_size = coroutine_stack_size(stack);
185 uc_stack->ss_sp = coroutine_stack_base((struct coroutine_stack *)stack);
187 #endif /* HAVE_UCONTEXT */
190 * Coroutine switching
194 void coroutine_init_(struct coroutine_state *cs,
195 void (*fn)(void *), void *arg,
196 struct coroutine_stack *stack)
198 getcontext (&cs->uc);
200 coroutine_uc_stack(&cs->uc.uc_stack, stack);
202 if (HAVE_POINTER_SAFE_MAKECONTEXT) {
203 makecontext(&cs->uc, (void *)fn, 1, arg);
205 ptrdiff_t si = ptr2int(arg);
206 ptrdiff_t mask = (1UL << (sizeof(int) * 8)) - 1;
208 int hi = si >> (sizeof(int) * 8);
210 makecontext(&cs->uc, (void *)fn, 2, lo, hi);
215 void coroutine_jump(const struct coroutine_state *to)
221 void coroutine_switch(struct coroutine_state *from,
222 const struct coroutine_state *to)
226 rc = swapcontext(&from->uc, &to->uc);
229 #endif /* HAVE_UCONTEXT */