[ccan] [PATCHv2 2/2] generator: Rewrite to use coroutine module
David Gibson
david at gibson.dropbear.id.au
Thu Dec 1 22:28:40 AEDT 2016
Use the new coroutine module to abstract away our dependence on
ucontext.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
---
ccan/generator/_info | 9 ++++++---
ccan/generator/generator.c | 39 ++++++++++++++++++------------------
ccan/generator/generator.h | 49 ++++++++++++++--------------------------------
3 files changed, 41 insertions(+), 56 deletions(-)
diff --git a/ccan/generator/_info b/ccan/generator/_info
index 11753a5..489b9dd 100644
--- a/ccan/generator/_info
+++ b/ccan/generator/_info
@@ -2,6 +2,8 @@
#include <stdio.h>
#include <string.h>
+#include <ccan/coroutine/coroutine.h>
+
/**
* generator - generators for C
*
@@ -56,18 +58,19 @@ int main(int argc, char *argv[])
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 d217665..656cbe7 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);
free(gen->base);
}
diff --git a/ccan/generator/generator.h b/ccan/generator/generator.h
index 121f14a..7122f55 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 <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 */
--
2.9.3
More information about the ccan
mailing list