Commit a2401780 authored by David Gibson's avatar David Gibson

generator: Rewrite to use coroutine module

Use the new coroutine module to abstract away our dependence on
ucontext.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 1ddc881f
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ccan/coroutine/coroutine.h>
/** /**
* generator - generators for C * generator - generators for C
* *
...@@ -55,19 +57,19 @@ int main(int argc, char *argv[]) ...@@ -55,19 +57,19 @@ int main(int argc, char *argv[])
return 1; return 1;
if (strcmp(argv[1], "depends") == 0) { if (strcmp(argv[1], "depends") == 0) {
printf("ccan/build_assert\n");
printf("ccan/ptrint\n");
printf("ccan/alignof\n"); printf("ccan/alignof\n");
printf("ccan/coroutine\n");
printf("ccan/cppmagic\n"); printf("ccan/cppmagic\n");
printf("ccan/compiler\n"); printf("ccan/compiler\n");
return 0; return 0;
} }
if (strcmp(argv[1], "ported") == 0) { if (strcmp(argv[1], "ported") == 0) {
#if HAVE_UCONTEXT #if COROUTINE_AVAILABLE
printf("\n"); printf("\n");
return 1;
#else #else
printf("Needs ucontext support\n"); printf("Needs coroutine support\n");
#endif #endif
} }
......
...@@ -10,10 +10,18 @@ ...@@ -10,10 +10,18 @@
#define DEFAULT_STATE_SIZE 8192 #define DEFAULT_STATE_SIZE 8192
#define STATE_ALIGN ALIGNOF(struct generator_) #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; char *base;
size_t size = DEFAULT_STATE_SIZE; size_t size = DEFAULT_STATE_SIZE;
size_t metasize = generator_metasize(retsize);
struct coroutine_stack *stack;
void *ret; void *ret;
struct generator_ *gen; struct generator_ *gen;
...@@ -22,33 +30,26 @@ void *generator_new_(generator_wrapper_ *fn, size_t retsize) ...@@ -22,33 +30,26 @@ void *generator_new_(generator_wrapper_ *fn, size_t retsize)
abort(); abort();
retsize = (retsize + STATE_ALIGN) & ~(STATE_ALIGN - 1); 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->base = base;
gen->complete = false; gen->complete = false;
getcontext(&gen->gen); coroutine_init(&gen->gen, fn, ret, stack);
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);
}
return ret; return ret;
} }
void generator_free_(void *ret) void generator_free_(void *ret, size_t retsize)
{ {
struct generator_ *gen = generator_state_(ret); 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); free(gen->base);
} }
...@@ -3,10 +3,6 @@ ...@@ -3,10 +3,6 @@
#define CCAN_GENERATOR_H #define CCAN_GENERATOR_H
#include "config.h" #include "config.h"
#if !HAVE_UCONTEXT
#error Generators require working ucontext.h functions
#endif
#if !HAVE_TYPEOF #if !HAVE_TYPEOF
#error Generators require typeof #error Generators require typeof
#endif #endif
...@@ -18,20 +14,22 @@ ...@@ -18,20 +14,22 @@
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.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/cppmagic/cppmagic.h>
#include <ccan/compiler/compiler.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 * Internals - included just for the use of inlines and macros
*/ */
struct generator_ { struct generator_ {
ucontext_t gen; struct coroutine_state gen;
ucontext_t caller; struct coroutine_state caller;
bool complete; bool complete;
void *base; void *base;
}; };
...@@ -51,15 +49,8 @@ struct generator_incomplete_; ...@@ -51,15 +49,8 @@ struct generator_incomplete_;
#define generator_rtype_(gen_) \ #define generator_rtype_(gen_) \
typeof((*(gen_))((struct generator_incomplete_ *)NULL)) typeof((*(gen_))((struct generator_incomplete_ *)NULL))
#if HAVE_POINTER_SAFE_MAKECONTEXT void *generator_new_(void (*fn)(void *), size_t retsize);
#define generator_wrapper_args_() void *ret void generator_free_(void *ret, size_t retsize);
#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);
/* /*
* API * API
...@@ -128,22 +119,15 @@ void generator_free_(void *ret); ...@@ -128,22 +119,15 @@ void generator_free_(void *ret);
#define generator_def_(name_, rtype_, storage_, ...) \ #define generator_def_(name_, rtype_, storage_, ...) \
static void name_##_generator_(rtype_ *ret_ \ static void name_##_generator_(rtype_ *ret_ \
generator_parms_inner_(__VA_ARGS__)); \ generator_parms_inner_(__VA_ARGS__)); \
static void name_##_generator__(generator_wrapper_args_()) \ static void name_##_generator__(void *ret) \
{ \ { \
struct generator_ *gen; \ struct generator_ *gen; \
UNNEEDED generator_argstruct_(__VA_ARGS__) *args; \ 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); \ gen = generator_state_(ret); \
args = generator_argp_(ret); \ args = generator_argp_(ret); \
name_##_generator_(ret generator_args_unpack_(__VA_ARGS__)); \ name_##_generator_(ret generator_args_unpack_(__VA_ARGS__)); \
gen->complete = true; \ gen->complete = true; \
setcontext(&gen->caller); \ coroutine_jump(&gen->caller); \
assert(0); \ assert(0); \
} \ } \
storage_ generator_t(rtype_) \ storage_ generator_t(rtype_) \
...@@ -184,10 +168,8 @@ void generator_free_(void *ret); ...@@ -184,10 +168,8 @@ void generator_free_(void *ret);
#define generator_yield(val_) \ #define generator_yield(val_) \
do { \ do { \
struct generator_ *gen_ = generator_state_(ret_); \ struct generator_ *gen_ = generator_state_(ret_); \
int rc; \
*(ret_) = (val_); \ *(ret_) = (val_); \
rc = swapcontext(&gen_->gen, &gen_->caller); \ coroutine_switch(&gen_->gen, &gen_->caller); \
assert(rc == 0); \
} while (0) } while (0)
/** /**
...@@ -202,13 +184,11 @@ void generator_free_(void *ret); ...@@ -202,13 +184,11 @@ void generator_free_(void *ret);
static inline void *generator_next_(void *ret_) static inline void *generator_next_(void *ret_)
{ {
struct generator_ *gen = generator_state_(ret_); struct generator_ *gen = generator_state_(ret_);
int rc;
if (gen->complete) if (gen->complete)
return NULL; return NULL;
rc = swapcontext(&gen->caller, &gen->gen); coroutine_switch(&gen->caller, &gen->gen);
assert(rc == 0);
return gen->complete ? NULL : ret_; return gen->complete ? NULL : ret_;
} }
...@@ -234,6 +214,7 @@ static inline void *generator_next_(void *ret_) ...@@ -234,6 +214,7 @@ static inline void *generator_next_(void *ret_)
}) })
#define generator_free(gen_) \ #define generator_free(gen_) \
generator_free_((generator_rtype_(gen_) *)(gen_)) generator_free_((generator_rtype_(gen_) *)(gen_), \
sizeof(generator_rtype_(gen_)))
#endif /* CCAN_GENERATOR_H */ #endif /* CCAN_GENERATOR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment