Skip to content

Instantly share code, notes, and snippets.

@Ronsor
Last active July 30, 2025 03:41
Show Gist options
  • Select an option

  • Save Ronsor/66ee016470fcb12231cd68c1647597f4 to your computer and use it in GitHub Desktop.

Select an option

Save Ronsor/66ee016470fcb12231cd68c1647597f4 to your computer and use it in GitHub Desktop.
Simple coroutine library for C
/*
* Coroutines for C
*
* Copyright (C) 2025 Ronsor Labs. All rights reserved.
*
* Anyone is free to use, copy, modify, or distribute this software for any
* purpose as long as this notice appears in all copies. This software is
* provided "as is" without any warranty, and the author will not be liable for
* any damages related to this software.
*/
#ifndef CO_H
#define CO_H
#define _(...) __VA_ARGS__
#define co_type(name) struct co_state_##name##_
#define co_new(name, ...) ((co_type(name)) { 0, { __VA_ARGS__ }, {} })
#define co_yield_(n) { _s->pc = n; return 1; case n:; }
#define co_ckpt_(n) { _s->pc = n; case n:; }
#if defined(__GNUC__) || defined(__clang__) || defined(__TINYC__)
#define co_yield() co_yield_(__COUNTER__+1)
#define co_ckpt() co_ckpt_(__COUNTER__+1)
#else
#define co_yield() co_yield_(__LINE__)
#define co_ckpt() co_ckpt_(__LINE__)
#endif
#define co_await(ctx, name, ...) \
{ \
ctx = co_new(name, __VA_ARGS__); \
while (name(&ctx)) { co_yield(); } \
}
#define co_args() _s->args
#define co_vars() _s->locals
#define co_arg(name) co_args().name
#define co_var(name) co_vars().name
#define $arg(name) co_arg(name)
#define $(name) co_var(name)
#define co(name, args_, locals_, body_) \
co_type(name) { \
int pc; \
struct args_ args; \
struct locals_ locals; \
}; \
int name(co_type(name) *_s) { \
switch (_s->pc) { \
case 0: \
body_; \
co_ckpt(); \
} \
return 0; \
}
#ifdef CO_TEST
#include <stdio.h>
co(simple_rng, _({ unsigned int s; }), _({}), _({
while (1) {
$arg(s) >>= 5;
$arg(s) *= 94712;
$arg(s) &= 0xffff;
co_yield();
}
}))
co(rng_printer, _({
const char *prefix;
unsigned int s;
}), _({
char str[64];
co_type(simple_rng) rng;
}), _({
$(rng) = co_new(simple_rng, $arg(s));
while (1) {
simple_rng(&$(rng));
sprintf($(str), "%s%u", $arg(prefix) ? $arg(prefix) : "", $(rng).args.s);
co_yield();
}
}))
int main() {
co_type(rng_printer) printer = co_new(rng_printer, "rng: ", 42);
for (int i = 0; i < 10; i++) {
rng_printer(&printer);
puts(printer.locals.str);
}
}
#endif
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment