diff options
| author | Tyge Løvset <[email protected]> | 2023-05-08 13:23:05 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2023-05-08 13:23:05 +0200 |
| commit | f8f544d8f5b805b9749f1e06fd7c1875b6115d48 (patch) | |
| tree | fbcb7f3ec9799bf537b8a8cc0ea014c7da398538 | |
| parent | b909bee0e400fa12908bc3d9bca447ea2a71864b (diff) | |
| download | STC-modified-f8f544d8f5b805b9749f1e06fd7c1875b6115d48.tar.gz STC-modified-f8f544d8f5b805b9749f1e06fd7c1875b6115d48.zip | |
Final coroutine API updates.
| -rw-r--r-- | docs/ccommon_api.md | 34 | ||||
| -rw-r--r-- | include/stc/algo/coroutine.h | 27 | ||||
| -rw-r--r-- | misc/examples/cointerleave.c | 13 |
3 files changed, 38 insertions, 36 deletions
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index daf21e56..fb29d642 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -354,35 +354,37 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Label for cleanup in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | -| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | -| `bool` | `cco_done(ctx)` | Is coroutine done? | -| | `cco_begin(ctx)` | Begin coroutine block | +| `bool` | `cco_suspended(co)` | Is coroutine in suspended state? | +| `bool` | `cco_done(co)` | Is coroutine done? | +| | `cco_begin(co)` | Begin coroutine block | | | `cco_end()` | End coroutine block | -| | `cco_end(retval)` | End coroutine block and return retval | -| | `cco_yield()` | Suspend execution | -| | `cco_yield(retval)` | Suspend execution and return retval | -| | `cco_await(promise)` | Suspend until promise is true | -| | `cco_await(promise, retval)` | Suspend with retval until promise is true | -| | `cco_call(ctx, corocall)` | Call coro async, suspend while not done | -| | `cco_call(ctx, corocall, retval)` | Call coro async, return retval on suspend | +| | `cco_end(ret)` | End coroutine block and return ret | +| | `cco_yield()` | Yield/suspend execution | +| | `cco_yield(ret)` | Yield/suspend execution and return ret | +| | `cco_yield_sub(subco, call)` | Yield if subco not done after call | +| | `cco_yield_sub(subco, call, ret)` | Yield with ret if subco alive after call | +| | `cco_await(promise)` | Wait/suspend until promise is true | +| | `cco_await(promise, ret)` | Wait/suspend with ret value | +| | `cco_await_sub(subco, call)` | Wait/suspend until subco call is done | +| | `cco_await_sub(subco, call, ret)` | Wait/suspend with ret on subco call done | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | -| | `cco_await_sem(sem, retval)` | Await with retval for the semaphore | -| | `csem_set(sem, long value)` | Set semaphore | +| | `cco_await_sem(sem, ret)` | Await with ret on the semaphore | +| | `csem_set(sem, long value)` | Set semaphore value | | | `csem_signal(sem)` | Signal the semaphore | | | Timers: | | | | `ctimer` | Timer type | | | `cco_await_timer(tm)` | Await for timer to expire | -| | `cco_await_timer(tm, retval)` | Await with retval for timer to expire | +| | `cco_await_timer(tm, ret)` | Await with ret for timer to expire | | | `ctimer_start(tm, long msecs)` | Start timer msecs milliseconds | | | `ctimer_restart(tm)` | Restart timer with same duration | | `bool` | `ctimer_expired(tm)` | Return true if timer is expired | | `long` | `ctimer_remaining(tm)` | Return milliseconds remaining | | | From caller side: | | -| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | -| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | -| `void` | `cco_run_blocked(ctx, corocall) { }` | Call coro blocked until done | +| `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_reset(co)` | Reset state to initial (for reuse) | +| `void` | `cco_run_blocked(co, corocall) { }` | Call coro blocked until done | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 942abc5a..83814605 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -71,28 +71,33 @@ enum { goto _begin; _begin: switch (*_state) { \ case 0: -#define cco_end(retval) \ +#define cco_end(ret) \ } \ *_state = cco_state_done; \ - return retval + return ret -#define cco_yield(retval) \ +#define cco_yield(ret) \ do { \ - *_state = __LINE__; return retval; \ + *_state = __LINE__; return ret; \ case __LINE__:; \ } while (0) +#define cco_yield_sub(...) c_MACRO_OVERLOAD(cco_yield_sub, __VA_ARGS__) +#define cco_yield_sub_2(co, call) cco_yield_sub_3(co, call, ) +#define cco_yield_sub_3(co, call, ret) \ + do { call; if (!cco_done(co)) cco_yield(ret); } while (0) + #define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) #define cco_await_1(promise) cco_await_2(promise, ) -#define cco_await_2(promise, retval) \ +#define cco_await_2(promise, ret) \ do { \ *_state = __LINE__; \ - case __LINE__: if (!(promise)) return retval; \ + case __LINE__: if (!(promise)) return ret; \ } while (0) -#define cco_call(...) c_MACRO_OVERLOAD(cco_call, __VA_ARGS__) -#define cco_call_2(co, call) cco_call_3(co, call, ) -#define cco_call_3(co, call, retval) cco_await_2((call, cco_done(co)), retval) +#define cco_await_sub(...) c_MACRO_OVERLOAD(cco_await_sub, __VA_ARGS__) +#define cco_await_sub_2(co, call) cco_await_sub_3(co, call, ) +#define cco_await_sub_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) #define cco_run_blocked(co, call) while (call, !cco_done(co)) @@ -127,9 +132,9 @@ typedef struct { #define cco_await_sem(...) c_MACRO_OVERLOAD(cco_await_sem, __VA_ARGS__) #define cco_await_sem_1(sem) cco_await_sem_2(sem, ) -#define cco_await_sem_2(sem, retval) \ +#define cco_await_sem_2(sem, ret) \ do { \ - cco_await_2((sem)->count > 0, retval); \ + cco_await_2((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 4fe89316..0ccf9ad7 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -11,7 +11,7 @@ struct GenValue { int cco_state; }; -static int next_value(struct GenValue* g) +static int get_value(struct GenValue* g) { cco_begin(g); for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) @@ -30,11 +30,8 @@ void interleaved(struct Generator* g) cco_begin(g); while (!cco_done(&g->x) || !cco_done(&g->y)) { - g->value = next_value(&g->x); - if (!cco_done(&g->x)) cco_yield(); - - g->value = next_value(&g->y); - if (!cco_done(&g->y)) cco_yield(); + cco_yield_sub(&g->x, g->value = get_value(&g->x)); + cco_yield_sub(&g->y, g->value = get_value(&g->y)); } cco_end(); } @@ -46,9 +43,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - while (1) { - interleaved(&g); - if (cco_done(&g)) break; + cco_run_blocked(&g, interleaved(&g)) { printf("%d ", g.value); } puts(""); |
