From a240178097376329b4567a6728952daa89362771 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Dec 2016 20:58:35 +1100 Subject: [PATCH] generator: Rewrite to use coroutine module Use the new coroutine module to abstract away our dependence on ucontext. Signed-off-by: David Gibson --- ccan/generator/_info | 10 ++++---- ccan/generator/generator.c | 39 +++++++++++++++--------------- ccan/generator/generator.h | 49 ++++++++++++-------------------------- 3 files changed, 41 insertions(+), 57 deletions(-) diff --git a/ccan/generator/_info b/ccan/generator/_info index 11753a5b..e40d7bbb 100644 --- a/ccan/generator/_info +++ b/ccan/generator/_info @@ -2,6 +2,8 @@ #include #include +#include + /** * generator - generators for C * @@ -55,19 +57,19 @@ int main(int argc, char *argv[]) return 1; if (strcmp(argv[1], "depends") == 0) { - printf("ccan/build_assert\n"); - printf("ccan/ptrint\n"); printf("ccan/alignof\n"); + printf("ccan/coroutine\n"); printf("ccan/cppmagic\n"); printf("ccan/compiler\n"); return 0; } if (strcmp(argv[1], "ported") == 0) { -#if HAVE_UCONTEXT +#if COROUTINE_AVAILABLE printf("\n"); + return 1; #else - printf("Needs ucontext support\n"); + printf("Needs coroutine support\n"); #endif } diff --git a/ccan/generator/generator.c b/ccan/generator/generator.c index d2176656..9c588474 100644 --- a/ccan/generator/generator.c +++ b/ccan/generator/generator.c @@ -10,10 +10,18 @@ #define DEFAULT_STATE_SIZE 8192 #define STATE_ALIGN ALIGNOF(struct generator_) -void *generator_new_(generator_wrapper_ *fn, size_t retsize) +static size_t generator_metasize(size_t retsize) +{ + retsize = (retsize + STATE_ALIGN) & ~(STATE_ALIGN - 1); + return sizeof(struct generator_) + retsize; +} + +void *generator_new_(void (*fn)(void *), size_t retsize) { char *base; size_t size = DEFAULT_STATE_SIZE; + size_t metasize = generator_metasize(retsize); + struct coroutine_stack *stack; void *ret; struct generator_ *gen; @@ -22,33 +30,26 @@ void *generator_new_(generator_wrapper_ *fn, size_t retsize) abort(); retsize = (retsize + STATE_ALIGN) & ~(STATE_ALIGN - 1); - ret = base + size - retsize; - gen = (struct generator_ *)ret - 1; + + stack = coroutine_stack_init(base, size, metasize); + gen = coroutine_stack_to_metadata(stack, metasize); + ret = gen + 1; gen->base = base; gen->complete = false; - getcontext(&gen->gen); - - gen->gen.uc_stack.ss_sp = gen->base; - gen->gen.uc_stack.ss_size = (char *)gen - base; - - if (HAVE_POINTER_SAFE_MAKECONTEXT) { - makecontext(&gen->gen, (void *)fn, 1, ret); - } else { - ptrdiff_t si = ptr2int(ret); - ptrdiff_t mask = (1UL << (sizeof(int) * 8)) - 1; - int lo = si & mask; - int hi = si >> (sizeof(int) * 8); - - makecontext(&gen->gen, (void *)fn, 2, lo, hi); - } + coroutine_init(&gen->gen, fn, ret, stack); return ret; } -void generator_free_(void *ret) +void generator_free_(void *ret, size_t retsize) { struct generator_ *gen = generator_state_(ret); + size_t metasize = generator_metasize(retsize); + struct coroutine_stack *stack; + + stack = coroutine_stack_from_metadata(gen, metasize); + coroutine_stack_release(stack, metasize); free(gen->base); } diff --git a/ccan/generator/generator.h b/ccan/generator/generator.h index 121f14aa..7122f554 100644 --- a/ccan/generator/generator.h +++ b/ccan/generator/generator.h @@ -3,10 +3,6 @@ #define CCAN_GENERATOR_H #include "config.h" -#if !HAVE_UCONTEXT -#error Generators require working ucontext.h functions -#endif - #if !HAVE_TYPEOF #error Generators require typeof #endif @@ -18,20 +14,22 @@ #include #include #include -#include -#include -#include #include #include +#include + +#if !COROUTINE_AVAILABLE +#error Generators require coroutines +#endif /* * Internals - included just for the use of inlines and macros */ struct generator_ { - ucontext_t gen; - ucontext_t caller; + struct coroutine_state gen; + struct coroutine_state caller; bool complete; void *base; }; @@ -51,15 +49,8 @@ struct generator_incomplete_; #define generator_rtype_(gen_) \ typeof((*(gen_))((struct generator_incomplete_ *)NULL)) -#if HAVE_POINTER_SAFE_MAKECONTEXT -#define generator_wrapper_args_() void *ret -#else -#define generator_wrapper_args_() int lo, int hi -#endif -typedef void generator_wrapper_(generator_wrapper_args_()); - -void *generator_new_(generator_wrapper_ *fn, size_t retsize); -void generator_free_(void *ret); +void *generator_new_(void (*fn)(void *), size_t retsize); +void generator_free_(void *ret, size_t retsize); /* * API @@ -128,22 +119,15 @@ void generator_free_(void *ret); #define generator_def_(name_, rtype_, storage_, ...) \ static void name_##_generator_(rtype_ *ret_ \ generator_parms_inner_(__VA_ARGS__)); \ - static void name_##_generator__(generator_wrapper_args_()) \ + static void name_##_generator__(void *ret) \ { \ struct generator_ *gen; \ UNNEEDED generator_argstruct_(__VA_ARGS__) *args; \ - CPPMAGIC_IFELSE(HAVE_POINTER_SAFE_MAKECONTEXT) \ - () \ - (ptrdiff_t hilo = ((ptrdiff_t)hi << (8*sizeof(int))) \ - + (ptrdiff_t)lo; \ - rtype_ *ret = (rtype_ *)int2ptr(hilo); \ - BUILD_ASSERT(sizeof(struct generator_ *) \ - <= 2*sizeof(int));) \ gen = generator_state_(ret); \ args = generator_argp_(ret); \ name_##_generator_(ret generator_args_unpack_(__VA_ARGS__)); \ gen->complete = true; \ - setcontext(&gen->caller); \ + coroutine_jump(&gen->caller); \ assert(0); \ } \ storage_ generator_t(rtype_) \ @@ -184,10 +168,8 @@ void generator_free_(void *ret); #define generator_yield(val_) \ do { \ struct generator_ *gen_ = generator_state_(ret_); \ - int rc; \ *(ret_) = (val_); \ - rc = swapcontext(&gen_->gen, &gen_->caller); \ - assert(rc == 0); \ + coroutine_switch(&gen_->gen, &gen_->caller); \ } while (0) /** @@ -202,13 +184,11 @@ void generator_free_(void *ret); static inline void *generator_next_(void *ret_) { struct generator_ *gen = generator_state_(ret_); - int rc; if (gen->complete) return NULL; - rc = swapcontext(&gen->caller, &gen->gen); - assert(rc == 0); + coroutine_switch(&gen->caller, &gen->gen); return gen->complete ? NULL : ret_; } @@ -234,6 +214,7 @@ static inline void *generator_next_(void *ret_) }) #define generator_free(gen_) \ - generator_free_((generator_rtype_(gen_) *)(gen_)) + generator_free_((generator_rtype_(gen_) *)(gen_), \ + sizeof(generator_rtype_(gen_))) #endif /* CCAN_GENERATOR_H */ -- 2.39.2