Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a boost.context call/cc backend #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/koishi.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ typedef struct koishi_coroutine {
* @brief Private data reserved for the implementation. Don't mess with it.
* @private
*/
void *_private[8];
void *_private[16];
#ifdef BUILDING_KOISHI
};
#else
Expand Down
36 changes: 36 additions & 0 deletions koishi_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,40 @@ void cancelled_caller_test(int *result) {
koishi_deinit(&outer);
}

void *counter(void *a) {
(void)a;

for(int i = 0;; ++i, koishi_yield(NULL)) {
printf("%i\n", i);
}
}

void *counter_creator(void *a) {
koishi_coroutine_t *co_counter = a;
koishi_init(co_counter, 0, counter);

printf("Counting from creator:\n");
koishi_resume(co_counter, NULL);
koishi_resume(co_counter, NULL);
koishi_resume(co_counter, NULL);

return NULL;
}

void resume_from_another_test(void) {
koishi_coroutine_t co_counter, co_creator;
koishi_init(&co_creator, 0, counter_creator);
koishi_resume(&co_creator, &co_counter);

printf("Counting from main:\n");
koishi_resume(&co_counter, NULL);
koishi_resume(&co_counter, NULL);
koishi_resume(&co_counter, NULL);

koishi_deinit(&co_creator);
koishi_deinit(&co_counter);
}

int main(int argc, char **argv) {
if(argc != 1) {
printf("%s takes no arguments.\n", argv[0]);
Expand Down Expand Up @@ -135,6 +169,8 @@ int main(int argc, char **argv) {
cancelled_caller_test(&result);
assert(result == 42);

resume_from_another_test();

printf("Done\n");
return 0;
}
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ option(
'auto',
'fcontext',
'boost_fcontext',
'boost_callcc',
'win32fiber',
'emscripten',
'ucontext_e2k',
Expand Down
115 changes: 115 additions & 0 deletions src/boost_callcc/boost_callcc.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@

#include <koishi.h>
#include <string.h>

extern "C" {
#include "../stack_alloc.h"
}

#include <boost/context/continuation.hpp>
namespace bctx = boost::context;

typedef struct boost_fiber {
bctx::continuation cc;
struct boost_fiber *from;
struct boost_fiber *next;
char *stack;
size_t stack_size;
} koishi_fiber_t;

#include "../fiber.h"

struct fake_allocator {
bctx::stack_context sctx = {};

fake_allocator(void *sp, size_t size) noexcept {
sctx.sp = (char*)sp + size;
sctx.size = size;
}

bctx::stack_context allocate() { return sctx; }
void deallocate(bctx::stack_context&) noexcept { }
};

static void koishi_fiber_init_callcc(koishi_fiber_t *fiber) {
fiber->from = nullptr;
fiber->next = nullptr;
new (&fiber->cc) bctx::continuation();

fiber->from = &koishi_active()->fiber;
fiber->cc = bctx::callcc(std::allocator_arg, fake_allocator(fiber->stack, fiber->stack_size),
[fiber](bctx::continuation && c) {
c = c.resume();
fiber->from->cc = std::move(c);

auto co = reinterpret_cast<koishi_coroutine_t*>(fiber);
co->userdata = co->entry(co->userdata);

koishi_return_to_caller(co, KOISHI_DEAD);

KOISHI_UNREACHABLE;
return bctx::continuation();
}
);
}

static void koishi_fiber_init(koishi_fiber_t *fiber, size_t min_stack_size) {
fiber->stack = (char*)alloc_stack(min_stack_size, &fiber->stack_size);
koishi_fiber_init_callcc(fiber);
}

static void koishi_fiber_init_main(koishi_fiber_t *fiber) {
new (&fiber->cc) bctx::continuation();
fiber->next = fiber;
}

static void koishi_fiber_recycle(koishi_fiber_t *fiber) {
fiber->cc.~continuation();
koishi_fiber_init_callcc(fiber);
}

static void koishi_fiber_deinit(koishi_fiber_t *fiber) {
fiber->cc.~continuation();

if(fiber->stack) {
free_stack(fiber->stack, fiber->stack_size);
fiber->stack = nullptr;
}
}

static void do_jump(koishi_fiber_t *from, koishi_fiber_t *to) {
to->from = from;
to->cc = to->cc.resume();
}

// TODO: Figure out how to avoid this stupid hack.
// The resume-from-another test fails without this.
static void stupid_trampoline(koishi_fiber_t *main) {
for(;;) {
auto next = main->next;

if(next == main) {
break;
}

main->next = main;
do_jump(main, next);
}
}

static void koishi_fiber_swap(koishi_fiber_t *from, koishi_fiber_t *to) {
auto main_fiber = &co_main.fiber;

if(main_fiber == from) {
do_jump(from, to);
stupid_trampoline(main_fiber);
} else {
main_fiber->next = to;
do_jump(from, main_fiber);
}
}

KOISHI_API void *koishi_get_stack(koishi_coroutine_t *co, size_t *stack_size) {
if(stack_size) *stack_size = co->fiber.stack_size;
return co->fiber.stack;
}
20 changes: 20 additions & 0 deletions src/boost_callcc/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

boost_callcc_supported = false

if not add_languages('cpp', required : false)
subdir_done()
endif

boostctx_dep = dependency('boost', modules : ['context'], required : false)

if not boostctx_dep.found()
subdir_done()
endif

boost_callcc_supported = true
boost_callcc_src = files('boost_callcc.cc')
boost_callcc_deps = [boostctx_dep]
boost_callcc_args = []
boost_callcc_external_args = []
boost_callcc_external_link_args = []

1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ koishi_deps = []
backends = [
'fcontext',
'boost_fcontext',
'boost_callcc',
'win32fiber',
'emscripten',
'ucontext_e2k',
Expand Down