generator: Rewrite to use coroutine module
authorDavid Gibson <david@gibson.dropbear.id.au>
Mon, 12 Dec 2016 09:58:35 +0000 (20:58 +1100)
committerDavid Gibson <david@gibson.dropbear.id.au>
Mon, 12 Dec 2016 09:58:35 +0000 (20:58 +1100)
Use the new coroutine module to abstract away our dependence on
ucontext.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
ccan/generator/_info
ccan/generator/generator.c
ccan/generator/generator.h

index 11753a5b8506b848de4238e24c9364db92e62308..e40d7bbb28c602c5e8b984a41ab203e5e82943de 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <ccan/coroutine/coroutine.h>
+
 /**
  * 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
        }
 
index d217665614819db7e585c41224a357f319c499a6..9c5884745d689a0a59d72ee87961a7bdd07bdc06 100644 (file)
 #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);
 }
index 121f14aa2915253677ae07271896c45570e20f6b..7122f554dd8987cde3ed83d7a03db9a380a36bec 100644 (file)
@@ -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
 #include <assert.h>
 #include <stddef.h>
 #include <stdbool.h>
-#include <ucontext.h>
 
-#include <ccan/ptrint/ptrint.h>
-#include <ccan/build_assert/build_assert.h>
 #include <ccan/cppmagic/cppmagic.h>
 #include <ccan/compiler/compiler.h>
+#include <ccan/coroutine/coroutine.h>
+
+#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 */