/* This file is part of asmc, a bootstrapping OS with minimal seed Copyright (C) 2019 Giovanni Mascellani https://gitlab.com/giomasce/asmc This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include typedef struct { bool runnable; void *stack; void (*target)(void*); void *ctx; jmp_buf caller_regs; jmp_buf callee_regs; } coro_t; coro_t *curr_coro; void coro_enter(coro_t *coro) { _force_assert(!curr_coro); _force_assert(coro->runnable); curr_coro = coro; printf("Entering coroutine...\n"); if (setjmp(coro->caller_regs) == 0) { longjmp(coro->callee_regs, 1); } printf("Exiting coroutine...\n"); curr_coro = NULL; } void coro_yield() { coro_t *coro = curr_coro; _force_assert(coro); _force_assert(curr_coro); if (setjmp(coro->callee_regs) == 0) { longjmp(coro->caller_regs, 1); } } void coro_wrapper() { coro_t *coro = curr_coro; _force_assert(coro); coro->target(coro->ctx); coro->runnable = false; coro_yield(); // We should not arrive here, because we cannot return! _force_assert(false); } coro_t *coro_init_with_stack_size(void (*target)(void*), void *ctx, size_t stack_size) { coro_t *ret = malloc(sizeof(coro_t)); memset(ret, 0, sizeof(coro_t)); ret->runnable = true; ret->stack = malloc(stack_size); ret->target = target; ret->ctx = ctx; ret->callee_regs.esp = ((unsigned long) ret->stack) + stack_size; ret->callee_regs.eip = (unsigned long) &coro_wrapper; printf("Creating coroutine with stack %x:%x and target %x\n", ret->stack, ret->stack + stack_size, target); return ret; } coro_t *coro_init(void (*target)(void*), void *ctx) { return coro_init_with_stack_size(target, ctx, 65536); } void coro_destroy(coro_t *coro) { _force_assert(!coro->runnable); free(coro->stack); free(coro); }