123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- /* This file is part of asmc, a bootstrapping OS with minimal seed
- Copyright (C) 2019 Giovanni Mascellani <gio@debian.org>
- 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 <https://www.gnu.org/licenses/>. */
- #include <assert.h>
- #include <stdbool.h>
- #include <string.h>
- #include <setjmp.h>
- #include <stdio.h>
- 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);
- }
|