Skip to content
/ coro Public

A very simple coroutine library for C based on getcontext

License

Notifications You must be signed in to change notification settings

LBPHacker/coro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Coro

Or: as if we don't have enough things to worry about

What (is all this)?

A very simple coroutine library for C that is semantically similar to Lua's, except there's no GC involved so you have to free coroutines yourself, which you can only do if they're dead (have terminated). Currently heavily depends on the getcontext family of functions, which seem to have been phased out of POSIX, very sad.

This library is not thread-safe, which, seeing as it's a coroutine library, shouldn't come as a surprise if you're considering using it. Regardless, you can configure (see below) the library to make its global state _Thread_local rather than static if you so wish, and if your compiler supports it, to get safety guarantees for at least the case in which your threads talk to each other very little and never try to use the same coroutines.

Why (would you do this)?

I just really wanted to get the itch to write some sort of coroutine library for C out of my system.

When (should I use this)?

Never, unless you're sure that the rest of your program can handle the sort of context transfers setcontext does. Especially not when using C++; this library will eat your exceptions for breakfast. There might be platform-dependent ways to solve this problem, but I haven't yet looked into these; PRs are welcome.

Also don't use this if you can't guarantee that you won't overflow the stacks allocated for your coroutines; see the code below. If you can't guarantee this but still would like to use the library, consider building (see way below) with -Duse_mmap_stack=true to have the library ask Linux for stacks that immediately and reliably crash your program with a SIGSEGV when overflowed, rather than break your allocator and cause a double free two weeks later. MAP_GROWSDOWN seems to be useless; requires further investigation.

Who (should I blame if my program dies)?

Yourself, see the license.

How (would I use this)?

The same way you'd do it in Lua. See coro.h and 03.c. But tl;dr:

#include <stdio.h>
#include <assert.h>

#include "coro.h"

struct context
{
	int input;
};

static void *cofunc(void *data)
{
	struct context *pctx = (struct context *)data;
	pctx->input *= pctx->input;
	printf("hello from cofunc\n");
	// * There first parameter of coro_yield is similar to the second parameter
	//   of coro_resume, see below.
	assert(!coro_yield((void **)&pctx));
	pctx->input += 42;
	return data;
}

static int func(int input)
{
	struct context ctx;
	struct context *pctx = &ctx;
	pctx->input = input;
	struct coro *co;
	// * All functions barring coro_status and coro_getudata return
	//   CORO_OK = 0 on success. See coro.h for other possible return values.
	// * Tell the library to allocate 0x1000 bytes to be used as stack
	//   by the new coroutine.
	assert(!coro_create(&co, cofunc, 0x1000U));
	printf("input is now %i\n", pctx->input);
	// * Pass a pointer to a pointer-sized area as the second parameter.
	//   This is necessary because not only do we want to send data to the
	//   coroutine, we also want to receive data from it.
	assert(!coro_resume(co, (void **)&pctx));
	printf("input is now %i\n", pctx->input);
	assert(!coro_resume(co, (void **)&pctx));
	printf("input is now %i\n", pctx->input);
	assert(!coro_free(co));
	return pctx->input;
}

int main(int argc, char *argv[])
{
	printf("result is %i\n", func(argc));
	return 0;
}

Build and install with Meson and Ninja like so:

cd coro
meson build
cd build
ninja test
sudo ninja install

If you wish to make the global state thread-local, configure the build site with use_thread_local set to true:

cd coro
meson -Duse_thread_local=true build
cd build
ninja test
sudo ninja install

The Meson script exports the dependency coro_dep. Installing also creates a coro.pc pkg-config file, which lets you link against this dependency with other build systems, and with dependency('coro') in Meson.

You can uninstall the library with:

sudo ninja uninstall

Build options:

name type default description
use_thread_local boolean true Make the global coro state _Thread_local rather than static
use_mmap_stack boolean true false Allocate coro stacks with mmap and MAP_GROWSDOWN (Linux) rather than malloc MAP_GROWSDOWN seems to be useless, see above

About

A very simple coroutine library for C based on getcontext

Resources

License

Stars

Watchers

Forks

Releases

No releases published