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 struct coroutine_stack {
22 /* Returns lowest stack addres, regardless of growth direction */
23 static UNNEEDED void *coroutine_stack_base(struct coroutine_stack *stack)
25 #if HAVE_STACK_GROWS_UPWARDS
26 return (char *)(stack + 1);
28 return (char *)stack - stack->size;
32 struct coroutine_stack *coroutine_stack_init(void *buf, size_t bufsize,
35 struct coroutine_stack *stack;
37 BUILD_ASSERT(COROUTINE_STK_OVERHEAD == sizeof(*stack));
39 BUILD_ASSERT(COROUTINE_MIN_STKSZ >= MINSIGSTKSZ);
42 if (bufsize < (COROUTINE_MIN_STKSZ + sizeof(*stack) + metasize))
45 #if HAVE_STACK_GROWS_UPWARDS
46 stack = (char *)buf + metasize;
48 stack = (struct coroutine_stack *)
49 ((char *)buf + bufsize - metasize) - 1;
52 stack->magic = COROUTINE_STACK_MAGIC;
53 stack->size = bufsize - sizeof(*stack) - metasize;
58 void coroutine_stack_release(struct coroutine_stack *stack, size_t metasize)
60 memset(stack, 0, sizeof(*stack));
63 struct coroutine_stack *coroutine_stack_check(struct coroutine_stack *stack,
66 if (stack && (stack->magic == COROUTINE_STACK_MAGIC)
67 && (stack->size >= COROUTINE_MIN_STKSZ))
72 fprintf(stderr, "%s: NULL coroutine stack\n", abortstr);
75 "%s: Bad coroutine stack at %p (magic=0x%"PRIx64" size=%zd)\n",
76 abortstr, stack, stack->magic, stack->size);
82 size_t coroutine_stack_size(const struct coroutine_stack *stack)
88 static void coroutine_uc_stack(stack_t *uc_stack,
89 const struct coroutine_stack *stack)
91 uc_stack->ss_size = coroutine_stack_size(stack);
92 uc_stack->ss_sp = coroutine_stack_base((struct coroutine_stack *)stack);
94 #endif /* HAVE_UCONTEXT */
101 void coroutine_init_(struct coroutine_state *cs,
102 void (*fn)(void *), void *arg,
103 struct coroutine_stack *stack)
105 getcontext (&cs->uc);
107 coroutine_uc_stack(&cs->uc.uc_stack, stack);
109 if (HAVE_POINTER_SAFE_MAKECONTEXT) {
110 makecontext(&cs->uc, (void *)fn, 1, arg);
112 ptrdiff_t si = ptr2int(arg);
113 ptrdiff_t mask = (1UL << (sizeof(int) * 8)) - 1;
115 int hi = si >> (sizeof(int) * 8);
117 makecontext(&cs->uc, (void *)fn, 2, lo, hi);
122 void coroutine_jump(const struct coroutine_state *to)
128 void coroutine_switch(struct coroutine_state *from,
129 const struct coroutine_state *to)
133 rc = swapcontext(&from->uc, &to->uc);
136 #endif /* HAVE_UCONTEXT */