d217665614819db7e585c41224a357f319c499a6
[ccan] / ccan / generator / generator.c
1 /* Licensed LGPLv2.1+ - see LICENSE file for details */
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <stddef.h>
5
6 #include <ccan/alignof/alignof.h>
7
8 #include <ccan/generator/generator.h>
9
10 #define DEFAULT_STATE_SIZE      8192
11 #define STATE_ALIGN             ALIGNOF(struct generator_)
12
13 void *generator_new_(generator_wrapper_ *fn, size_t retsize)
14 {
15         char *base;
16         size_t size = DEFAULT_STATE_SIZE;
17         void *ret;
18         struct generator_ *gen;
19
20         base = malloc(size);
21         if (!base)
22                 abort();
23
24         retsize = (retsize + STATE_ALIGN) & ~(STATE_ALIGN - 1);
25         ret = base + size - retsize;
26         gen = (struct generator_ *)ret - 1;
27
28         gen->base = base;
29         gen->complete = false;
30
31         getcontext(&gen->gen);
32
33         gen->gen.uc_stack.ss_sp = gen->base;
34         gen->gen.uc_stack.ss_size = (char *)gen - base;
35
36         if (HAVE_POINTER_SAFE_MAKECONTEXT) {
37                 makecontext(&gen->gen, (void *)fn, 1, ret);
38         } else {
39                 ptrdiff_t si = ptr2int(ret);
40                 ptrdiff_t mask = (1UL << (sizeof(int) * 8)) - 1;
41                 int lo = si & mask;
42                 int hi = si >> (sizeof(int) * 8);
43
44                 makecontext(&gen->gen, (void *)fn, 2, lo, hi);
45         }
46
47         return ret;
48 }
49
50 void generator_free_(void *ret)
51 {
52         struct generator_ *gen = generator_state_(ret);
53         free(gen->base);
54 }