summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTyge Løvset <[email protected]>2023-07-02 22:01:46 +0200
committerTyge Løvset <[email protected]>2023-07-02 23:18:10 +0200
commite25dec033773ab713a7593a923e2c83745be0b9a (patch)
tree174c9edfee09fb90b18ac17661cc9a8f291fa83c
parentfc43b14f706f22e3933b3d225819ea68f7ce2679 (diff)
downloadSTC-modified-e25dec033773ab713a7593a923e2c83745be0b9a.tar.gz
STC-modified-e25dec033773ab713a7593a923e2c83745be0b9a.zip
Update in coroutine API. cco_yield, cco_await, cco_await_on, cco_block_on has changed. cco_final: renamed => cco_cleanup:
Reverted i_retain template param back to => i_more.
-rw-r--r--docs/ccommon_api.md62
-rw-r--r--include/stc/algo/coroutine.h120
-rw-r--r--include/stc/algo/sort.h2
-rw-r--r--include/stc/cdeq.h6
-rw-r--r--include/stc/priv/template2.h4
-rw-r--r--misc/benchmarks/various/csort_bench.c2
-rw-r--r--misc/examples/cointerleave.c11
-rw-r--r--misc/examples/coread.c7
-rw-r--r--misc/examples/coroutines.c54
-rw-r--r--misc/examples/dining_philosophers.c16
-rw-r--r--misc/examples/generator.c5
-rw-r--r--misc/examples/scheduler.c34
-rw-r--r--misc/examples/triples.c10
13 files changed, 189 insertions, 144 deletions
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md
index c9c65156..b30bdda6 100644
--- a/docs/ccommon_api.md
+++ b/docs/ccommon_api.md
@@ -222,11 +222,11 @@ int main() {
}
```
Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is
-possible and very fast. Note that `i_retain` must be defined to retain specified template parameters for use by sort:
+possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort:
```c
#define i_type MyDeq
#define i_val int
-#define i_retain
+#define i_more
#include <stc/cdeq.h> // deque
#include <stc/algo/sort.h>
#include <stdio.h>
@@ -313,6 +313,7 @@ the gcd() function. It also ensures that it stops when the diagonal size >= 100:
[ [Run this code](https://godbolt.org/z/coqqrfbd5) ]
```c
#include <stc/calgo.h>
+#include <stdio.h>
struct triples {
int n; // input: max number of triples to be generated.
@@ -320,22 +321,23 @@ struct triples {
int cco_state; // required member
};
-bool triples(struct triples* i) { // coroutine
+int triples(struct triples* i) { // coroutine
cco_routine(i) {
for (i->c = 5; i->n; ++i->c) {
for (i->a = 1; i->a < i->c; ++i->a) {
for (i->b = i->a + 1; i->b < i->c; ++i->b) {
if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) {
- cco_yield(false);
- if (--i->n == 0) cco_return;
+ cco_yield();
+ if (--i->n == 0)
+ cco_return;
}
}
}
}
- cco_final:
+ cco_cleanup:
puts("done");
}
- return true;
+ return 0;
}
int gcd(int a, int b) { // greatest common denominator
@@ -352,7 +354,7 @@ int main()
struct triples t = {.n=INT32_MAX};
int n = 0;
- while (!triples(&t)) {
+ while (triples(&t)) {
// Skip triples with GCD(a,b) > 1
if (gcd(t.a, t.b) > 1)
continue;
@@ -366,28 +368,36 @@ int main()
}
```
### Coroutine API
-**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead.
-To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again.
+To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again.
+
+**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement; either use
+`if-else-if` constructs, or `cco_switch / cco_case / cco_default` for switch-emulation instead.
| | Function / operator | Description |
|:----------|:-------------------------------------|:----------------------------------------|
-| | `cco_final:` | Label for cleanup in coroutine |
+| | Function / 'keywords': | |
+|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines |
+| | Function / 'keywords': | |
+| | `cco_cleanup:` | Label for cleanup position in coroutine |
| `bool` | `cco_done(co)` | Is coroutine done? |
-| | `cco_routine(co) { ... }` | The coroutine closure |
-| | `cco_yield()` | Yield/suspend execution |
-| | `cco_yield(ret)` | Yield/suspend execution and return ret |
-| | `cco_await(promise)` | Await/suspend until promise is true |
-| | `cco_await(promise, ret)` | Await/suspend with ret value |
-| | `cco_return` | Replaces return. Jump to cco_final: if exist|
-| | `cco_return_v(val)` | Yield final value, enter final-state |
-| | `cco_closure(Ret, Closure, ...)` | Define coroutine closure struct. |
-| `void` | `cco_await_on(closure) { }` | Await on closure to finish |
-| `void` | `cco_await_on(co, func) { }` | Await on func(co) to finish |
+| | `cco_routine(co) { }` | The coroutine scope |
+| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)|
+| | `cco_yield_v();` | Yield/suspend execution (return void) |
+| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) |
+| | `cco_yield_final();` | Yield final time, enables cleanup-state |
+| | `cco_yield_final(val);` | Yield a final value (e.g. CCO_ERROR) |
+| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)|
+| | `cco_await_v(condition);` | Suspend until condition is true (return void) |
+| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)|
+| | `cco_await_on(cocall);` | Await on sub-coroutine to finish |
+| | `cco_return;` | Return from coroutine (inside cco_routine) |
+| | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) |
| | Semaphores: | |
| | `cco_sem` | Semaphore type |
+| `cco_sem` | `cco_sem_from(long value)` | Create semaphore |
+| | `cco_sem_set(sem, long value)` | Set semaphore value |
| | `cco_sem_await(sem)` | Await for the semaphore count > 0 |
| | `cco_sem_await(sem, ret)` | Await with ret on the semaphore |
-| `cco_sem` | `cco_sem_init(long value)` | Set semaphore value |
| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) |
| | Timers: | |
| | `cco_timer` | Timer type |
@@ -401,11 +411,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c
| | From caller side: | |
| `void` | `cco_stop(co)` | Next call of coroutine finalizes |
| `void` | `cco_reset(co)` | Reset state to initial (for reuse) |
-| `void` | `cco_block_on(closure) { }` | Run blocking until closure is finished |
-| `void` | `cco_block_on(co, func) { }` | Run blocking until func is finished |
+| `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished |
+| `void` | `cco_block_on(cocall, int *result) { }`| Run blocking until cocall is finished |
| | Time functions: | |
| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch |
| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) |
+| | Emulate switch: | |
+| | `cco_switch(x) { }` | Like switch syntax |
+| | `cco_case(val) { }` | Braces are required. Fall-through if no break; |
+| | `cco_default { }` | Default action |
---
## RAII scope macros
diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h
index e20fd8ad..198b0439 100644
--- a/include/stc/algo/coroutine.h
+++ b/include/stc/algo/coroutine.h
@@ -32,22 +32,22 @@ struct iterpair {
int cco_state; // required member
};
-bool iterpair(struct iterpair* I) {
+int iterpair(struct iterpair* I) {
cco_routine(I) {
for (I->x = 0; I->x < I->max_x; I->x++)
for (I->y = 0; I->y < I->max_y; I->y++)
- cco_yield(false);
+ cco_yield();
- cco_final: // required if there is cleanup code
+ cco_cleanup: // required if there is cleanup code
puts("final");
}
- return true; // finished
+ return 0; // CCO_DONE
}
int main(void) {
struct iterpair it = {.max_x=3, .max_y=3};
int n = 0;
- while (!iterpair(&it))
+ while (iterpair(&it))
{
printf("%d %d\n", it.x, it.y);
// example of early stop:
@@ -59,12 +59,19 @@ int main(void) {
#include "../ccommon.h"
enum {
- cco_state_final = -1,
- cco_state_done = -2,
+ CCO_STATE_CLEANUP = -1,
+ CCO_STATE_DONE = -2,
};
+typedef enum {
+ CCO_DONE = 0,
+ CCO_YIELD = 1,
+ CCO_AWAIT = 2,
+ CCO_ERROR = -1,
+} cco_result;
#define cco_initial(co) ((co)->cco_state == 0)
-#define cco_done(co) ((co)->cco_state == cco_state_done)
+#define cco_suspended(co) ((co)->cco_state > 0)
+#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE)
/* Emulate switch in coro: always use { } after cco_case(val) and cco_default. */
#define cco_switch(x) for (long long _sw = (long long)(x), _b=0; !_b; _b=1)
@@ -72,83 +79,97 @@ enum {
#define cco_default
#define cco_routine(co) \
- for (int *_state = &(co)->cco_state; *_state != cco_state_done; *_state = cco_state_done) \
+ for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \
_resume: switch (*_state) case 0: // thanks, @liigo!
-#define cco_yield(ret) \
+#define cco_yield() cco_yield_v(CCO_YIELD)
+#define cco_yield_v(ret) \
do { \
*_state = __LINE__; return ret; goto _resume; \
case __LINE__:; \
} 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, ret) \
+#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT)
+#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__)
+#define cco_await_v_1(promise) cco_await_v_2(promise, )
+#define cco_await_v_2(promise, ret) \
do { \
*_state = __LINE__; \
case __LINE__: if (!(promise)) {return ret; goto _resume;} \
} while (0)
-#define cco_closure(Ret, Closure, ...) \
- struct Closure { \
- Ret (*cco_fn)(struct Closure*); \
- int cco_state; \
- __VA_ARGS__ \
- }
-
-typedef struct cco_base {
- void (*cco_fn)(struct cco_base*);
- int cco_state;
-} cco_base;
-
-#define cco_base_cast(closure) \
- ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state)))
-
-#define cco_resume(closure) (closure)->cco_fn(closure)
-#define cco_await_on(...) c_MACRO_OVERLOAD(cco_await_on, __VA_ARGS__)
-#define cco_await_on_1(closure) cco_await_2((cco_resume(closure), cco_done(closure)), )
-#define cco_await_on_2(co, func) cco_await_2((func(co), cco_done(co)), )
+/* cco_await_on(): assumes coroutine returns a cco_result value (int) */
+#define cco_await_on(corocall) \
+ do { \
+ *_state = __LINE__; \
+ case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \
+ } while (0)
+/* cco_block_on(): assumes coroutine returns a cco_result value (int) */
#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__)
-#define cco_block_on_1(closure) while (cco_resume(closure), !cco_done(closure))
-#define cco_block_on_2(co, func) while (func(co), !cco_done(co))
+#define cco_block_on_1(corocall) while (corocall != CCO_DONE)
+#define cco_block_on_2(corocall, res) while ((*(res) = (corocall)) != CCO_DONE)
-#define cco_final \
- *_state = cco_state_final; case cco_state_final
+#define cco_cleanup \
+ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP
#define cco_return \
do { \
- *_state = *_state >= 0 ? cco_state_final : cco_state_done; \
+ *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \
goto _resume; \
} while (0)
-#define cco_return_v(value) \
+#define cco_yield_final() cco_yield_final_v(CCO_YIELD)
+#define cco_yield_final_v(value) \
do { \
- *_state = *_state >= 0 ? cco_state_final : cco_state_done; \
+ *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \
return value; \
} while (0)
#define cco_stop(co) \
do { \
int* _s = &(co)->cco_state; \
- if (*_s > 0) *_s = cco_state_final; \
- else if (*_s == 0) *_s = cco_state_done; \
+ if (*_s > 0) *_s = CCO_STATE_CLEANUP; \
+ else if (*_s == 0) *_s = CCO_STATE_DONE; \
} while (0)
#define cco_reset(co) \
(void)((co)->cco_state = 0)
/*
+ * Closure (optional)
+ */
+
+#define cco_closure(Name, ...) \
+ struct Name { \
+ int (*cco_fn)(struct Name*); \
+ int cco_state; \
+ __VA_ARGS__ \
+ }
+
+typedef struct cco_base {
+ int (*cco_fn)(struct cco_base*);
+ int cco_state;
+} cco_base;
+
+#define cco_resume(closure) \
+ (closure)->cco_fn(closure)
+
+#define cco_cast(closure) \
+ ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state)))
+
+/*
* Semaphore
*/
typedef struct { intptr_t count; } cco_sem;
-#define cco_sem_await(...) c_MACRO_OVERLOAD(cco_sem_await, __VA_ARGS__)
-#define cco_sem_await_1(sem) cco_sem_await_2(sem, )
-#define cco_sem_await_2(sem, ret) \
+#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT)
+#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__)
+#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, )
+#define cco_sem_await_v_2(sem, ret) \
do { \
- cco_await_2((sem)->count > 0, ret); \
+ cco_await_v_2((sem)->count > 0, ret); \
--(sem)->count; \
} while (0)
@@ -197,12 +218,13 @@ typedef struct { intptr_t count; } cco_sem;
typedef struct { double interval, start; } cco_timer;
-#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__)
-#define cco_timer_await_2(tm, sec) cco_timer_await_3(tm, sec, )
-#define cco_timer_await_3(tm, sec, ret) \
+#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT)
+#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__)
+#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, )
+#define cco_timer_await_v_3(tm, sec, ret) \
do { \
cco_timer_start(tm, sec); \
- cco_await_2(cco_timer_expired(tm), ret); \
+ cco_await_v_2(cco_timer_expired(tm), ret); \
} while (0)
static inline void cco_timer_start(cco_timer* tm, double sec) {
diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h
index 002e6499..8365ccc5 100644
--- a/include/stc/algo/sort.h
+++ b/include/stc/algo/sort.h
@@ -44,7 +44,7 @@ int main() {
// ex2:
#define i_val int
#define i_type IDeq
-#define i_retain // retain input template params to be reused by sort.h
+#define i_more // retain input template params to be reused by sort.h
#include <stc/cdeq.h>
#include <stc/algo/sort.h>
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index 2db040f1..bac40f90 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -23,11 +23,11 @@
#define _i_prefix cdeq_
#define _pop _pop_front
#define _pull _pull_front
-#ifdef i_retain
+#ifdef i_more
#include "cqueue.h"
- #define i_retain
+ #define i_more
#else
- #define i_retain
+ #define i_more
#include "cqueue.h"
#endif
#undef _pop
diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h
index bd8bc5fc..def5d01e 100644
--- a/include/stc/priv/template2.h
+++ b/include/stc/priv/template2.h
@@ -20,8 +20,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifdef i_retain
-#undef i_retain
+#ifdef i_more
+#undef i_more
#else
#undef i_type
#undef i_tag
diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c
index 93034dde..d434693f 100644
--- a/misc/benchmarks/various/csort_bench.c
+++ b/misc/benchmarks/various/csort_bench.c
@@ -8,7 +8,7 @@
#define NDEBUG
#define i_type Ints
#define i_val int
-#define i_retain
+#define i_more
#include <stc/cvec.h>
#include <stc/algo/sort.h>
diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c
index 1ba7b861..61562a5f 100644
--- a/misc/examples/cointerleave.c
+++ b/misc/examples/cointerleave.c
@@ -15,7 +15,7 @@ static int get_value(struct GenValue* g)
{
cco_routine(g) {
for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it))
- cco_yield(*g->it.ref);
+ cco_yield_v(*g->it.ref);
}
return -1;
}
@@ -26,10 +26,10 @@ struct Generator {
int value;
};
-void interleaved(struct Generator* g)
+cco_result interleaved(struct Generator* g)
{
cco_routine(g) {
- do {
+ while (!(cco_done(&g->x) & cco_done(&g->y))) {
g->value = get_value(&g->x);
if (!cco_done(&g->x))
cco_yield();
@@ -37,8 +37,9 @@ void interleaved(struct Generator* g)
g->value = get_value(&g->y);
if (!cco_done(&g->y))
cco_yield();
- } while (!(cco_done(&g->x) & cco_done(&g->y)));
+ }
}
+ return CCO_DONE;
}
void Use(void)
@@ -48,7 +49,7 @@ void Use(void)
struct Generator g = {{&a}, {&b}};
- cco_block_on(&g, interleaved) {
+ cco_block_on(interleaved(&g)) {
printf("%d ", g.value);
}
puts("");
diff --git a/misc/examples/coread.c b/misc/examples/coread.c
index 622228c0..a13f6be5 100644
--- a/misc/examples/coread.c
+++ b/misc/examples/coread.c
@@ -12,7 +12,7 @@ struct file_read {
cstr line;
};
-void file_read(struct file_read* g)
+int file_read(struct file_read* g)
{
cco_routine(g) {
g->fp = fopen(g->filename, "r");
@@ -21,18 +21,19 @@ void file_read(struct file_read* g)
cco_await(!cstr_getline(&g->line, g->fp));
- cco_final:
+ cco_cleanup:
printf("finish\n");
cstr_drop(&g->line);
if (g->fp) fclose(g->fp);
}
+ return 0;
}
int main(void)
{
struct file_read g = {__FILE__};
int n = 0;
- cco_block_on(&g, file_read)
+ cco_block_on(file_read(&g))
{
printf("%3d %s\n", ++n, cstr_str(&g.line));
//if (n == 10) cco_stop(&g);
diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c
index 1e900fa1..b8dfaa13 100644
--- a/misc/examples/coroutines.c
+++ b/misc/examples/coroutines.c
@@ -4,27 +4,26 @@
// Demonstrate to call another coroutine from a coroutine:
// First create prime generator, then call fibonacci sequence:
-typedef long long llong;
-bool is_prime(int64_t i) {
- for (llong j=2; j*j <= i; ++j)
+bool is_prime(long long i) {
+ for (long long j=2; j*j <= i; ++j)
if (i % j == 0) return false;
return true;
}
struct prime {
int count, idx;
- llong result, pos;
+ long long result, pos;
int cco_state;
};
-bool prime(struct prime* g) {
+int prime(struct prime* g) {
cco_routine(g) {
if (g->result < 2) g->result = 2;
if (g->result == 2) {
if (g->count-- == 0) cco_return;
++g->idx;
- cco_yield(false);
+ cco_yield();
}
g->result += !(g->result & 1);
for (g->pos = g->result; g->count > 0; g->pos += 2) {
@@ -32,13 +31,13 @@ bool prime(struct prime* g) {
--g->count;
++g->idx;
g->result = g->pos;
- cco_yield(false);
+ cco_yield();
}
}
- cco_final:
+ cco_cleanup:
printf("final prm\n");
}
- return true;
+ return 0;
}
@@ -46,13 +45,14 @@ bool prime(struct prime* g) {
struct fibonacci {
int count, idx;
- llong result, b;
+ long long result, b;
int cco_state;
};
-bool fibonacci(struct fibonacci* g) {
+int fibonacci(struct fibonacci* g) {
assert(g->count < 94);
+ long long sum;
cco_routine(g) {
g->idx = 0;
g->result = 0;
@@ -61,17 +61,17 @@ bool fibonacci(struct fibonacci* g) {
if (g->count-- == 0)
cco_return;
if (++g->idx > 1) {
- // NB! locals lasts only until next cco_yield/cco_await!
- llong sum = g->result + g->b;
+ // NB! locals lasts only until next yield/await!
+ sum = g->result + g->b;
g->result = g->b;
g->b = sum;
}
- cco_yield(false);
+ cco_yield();
}
- cco_final:
+ cco_cleanup:
printf("final fib\n");
}
- return true;
+ return 0;
}
// Combine
@@ -82,29 +82,31 @@ struct combined {
int cco_state;
};
-
-void combined(struct combined* g) {
+int combined(struct combined* g) {
cco_routine(g) {
- cco_await(prime(&g->prm));
- cco_await(fibonacci(&g->fib));
+ cco_await_on(prime(&g->prm));
+ cco_await_on(fibonacci(&g->fib));
// Reuse the g->prm context and extend the count:
g->prm.count = 8, g->prm.result += 2;
cco_reset(&g->prm);
- cco_await(prime(&g->prm));
+ cco_await_on(prime(&g->prm));
- cco_final:
+ cco_cleanup:
puts("final combined");
}
+ return 0;
}
int main(void)
{
struct combined c = {.prm={.count=8}, .fib={14}};
+ int res;
- cco_block_on(&c, combined) {
- printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
- c.prm.idx, c.prm.result,
- c.fib.idx, c.fib.result);
+ cco_block_on(combined(&c), &res) {
+ if (res == CCO_YIELD)
+ printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
+ c.prm.idx, c.prm.result,
+ c.fib.idx, c.fib.result);
}
}
diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c
index e13eb055..61fe67fb 100644
--- a/misc/examples/dining_philosophers.c
+++ b/misc/examples/dining_philosophers.c
@@ -27,7 +27,7 @@ struct Dining {
// Philosopher coroutine
-void philosopher(struct Philosopher* p)
+int philosopher(struct Philosopher* p)
{
double duration;
cco_routine(p) {
@@ -48,14 +48,15 @@ void philosopher(struct Philosopher* p)
cco_sem_release(p->right_fork);
}
- cco_final:
+ cco_cleanup:
printf("Philosopher %d finished\n", p->id);
}
+ return 0;
}
// Dining coroutine
-void dining(struct Dining* d)
+int dining(struct Dining* d)
{
cco_routine(d) {
for (int i = 0; i < num_forks; ++i)
@@ -68,20 +69,21 @@ void dining(struct Dining* d)
}
while (1) {
- // per-"frame" logic update of all philosophers states
+ // per-"frame" logic resume each philosopher
for (int i = 0; i < num_philosophers; ++i) {
philosopher(&d->ph[i]);
}
cco_yield(); // suspend, return control back to main
}
- cco_final:
+ cco_cleanup:
for (int i = 0; i < num_philosophers; ++i) {
cco_stop(&d->ph[i]);
philosopher(&d->ph[i]);
}
puts("Dining finished");
}
+ return 0;
}
int main()
@@ -89,13 +91,13 @@ int main()
struct Dining dine;
cco_reset(&dine);
int n=0;
- cco_timer tm = cco_timer_from(10.0); // seconds
+ cco_timer tm = cco_timer_from(15.0); // seconds
csrand((uint64_t)time(NULL));
while (!cco_done(&dine)) {
if (cco_timer_expired(&tm))
cco_stop(&dine);
- dining(&dine);
+ dining(&dine); // resume
cco_sleep(0.001);
++n;
}
diff --git a/misc/examples/generator.c b/misc/examples/generator.c
index 6b4b8407..3ff7a645 100644
--- a/misc/examples/generator.c
+++ b/misc/examples/generator.c
@@ -14,7 +14,7 @@ typedef struct {
int cco_state;
} Triple_iter;
-void Triple_next(Triple_iter* it) {
+int Triple_next(Triple_iter* it) {
Triple_value* g = it->ref;
cco_routine(it)
{
@@ -29,9 +29,10 @@ void Triple_next(Triple_iter* it) {
}
}
}
- cco_final:
+ cco_cleanup:
it->ref = NULL;
}
+ return 0;
}
Triple_iter Triple_begin(Triple* g) {
diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c
index 04f7ba4a..c1168850 100644
--- a/misc/examples/scheduler.c
+++ b/misc/examples/scheduler.c
@@ -2,9 +2,11 @@
#include <stdio.h>
#include <stc/calgo.h>
-cco_closure(bool, Task,
+struct Task {
+ int (*fn)(struct Task*);
+ int cco_state;
struct Scheduler* sched;
-);
+};
#define i_type Scheduler
#define i_val struct Task
@@ -16,49 +18,49 @@ static bool schedule(Scheduler* sched)
Scheduler_pop(sched);
if (!cco_done(&task))
- cco_resume(&task);
+ task.fn(&task);
return !Scheduler_empty(sched);
}
-static bool push_task(const struct Task* task)
+static int push_task(const struct Task* task)
{
Scheduler_push(task->sched, *task);
- return false;
+ return CCO_YIELD;
}
-static bool taskA(struct Task* task)
+static int taskA(struct Task* task)
{
cco_routine(task) {
puts("Hello, from task A");
- cco_yield(push_task(task));
+ cco_yield_v(push_task(task));
puts("A is back doing work");
- cco_yield(push_task(task));
+ cco_yield_v(push_task(task));
puts("A is back doing more work");
- cco_yield(push_task(task));
+ cco_yield_v(push_task(task));
puts("A is back doing even more work");
}
- return true;
+ return 0;
}
-static bool taskB(struct Task* task)
+static int taskB(struct Task* task)
{
cco_routine(task) {
puts("Hello, from task B");
- cco_yield(push_task(task));
+ cco_yield_v(push_task(task));
puts("B is back doing work");
- cco_yield(push_task(task));
+ cco_yield_v(push_task(task));
puts("B is back doing more work");
}
- return true;
+ return 0;
}
void Use(void)
{
Scheduler scheduler = c_init(Scheduler, {
- {.cco_fn=taskA, .sched=&scheduler},
- {.cco_fn=taskB, .sched=&scheduler},
+ {.fn=taskA, .sched=&scheduler},
+ {.fn=taskB, .sched=&scheduler},
});
while (schedule(&scheduler)) {}
diff --git a/misc/examples/triples.c b/misc/examples/triples.c
index 17e3d40b..a8ca6b47 100644
--- a/misc/examples/triples.c
+++ b/misc/examples/triples.c
@@ -32,7 +32,7 @@ struct triples {
int cco_state;
};
-void triples_coro(struct triples* t) {
+int triples_coro(struct triples* t) {
cco_routine(t) {
t->count = 0;
for (t->c = 5; t->size; ++t->c) {
@@ -46,9 +46,10 @@ void triples_coro(struct triples* t) {
}
}
}
- cco_final:
+ cco_cleanup:
puts("done");
}
+ return 0;
}
int main()
@@ -57,11 +58,10 @@ int main()
triples_vanilla(5);
puts("\nCoroutine triples:");
- struct triples t = {INT32_MAX};
+ struct triples t = {.size=INT32_MAX};
int n = 0;
- while (!cco_done(&t)) {
- triples_coro(&t);
+ while (triples_coro(&t)) {
if (gcd(t.a, t.b) > 1)
continue;
if (t.c < 100)