coros.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /* This file is part of asmc, a bootstrapping OS with minimal seed
  2. Copyright (C) 2019 Giovanni Mascellani <gio@debian.org>
  3. https://gitlab.com/giomasce/asmc
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. #include <assert.h>
  15. #include <stdbool.h>
  16. #include <string.h>
  17. #include <setjmp.h>
  18. #include <stdio.h>
  19. typedef struct {
  20. bool runnable;
  21. void *stack;
  22. void (*target)(void*);
  23. void *ctx;
  24. jmp_buf caller_regs;
  25. jmp_buf callee_regs;
  26. } coro_t;
  27. coro_t *curr_coro;
  28. void coro_enter(coro_t *coro) {
  29. _force_assert(!curr_coro);
  30. _force_assert(coro->runnable);
  31. curr_coro = coro;
  32. printf("Entering coroutine...\n");
  33. if (setjmp(coro->caller_regs) == 0) {
  34. longjmp(coro->callee_regs, 1);
  35. }
  36. printf("Exiting coroutine...\n");
  37. curr_coro = NULL;
  38. }
  39. void coro_yield() {
  40. coro_t *coro = curr_coro;
  41. _force_assert(coro);
  42. _force_assert(curr_coro);
  43. if (setjmp(coro->callee_regs) == 0) {
  44. longjmp(coro->caller_regs, 1);
  45. }
  46. }
  47. void coro_wrapper() {
  48. coro_t *coro = curr_coro;
  49. _force_assert(coro);
  50. coro->target(coro->ctx);
  51. coro->runnable = false;
  52. coro_yield();
  53. // We should not arrive here, because we cannot return!
  54. _force_assert(false);
  55. }
  56. coro_t *coro_init_with_stack_size(void (*target)(void*), void *ctx, size_t stack_size) {
  57. coro_t *ret = malloc(sizeof(coro_t));
  58. memset(ret, 0, sizeof(coro_t));
  59. ret->runnable = true;
  60. ret->stack = malloc(stack_size);
  61. ret->target = target;
  62. ret->ctx = ctx;
  63. ret->callee_regs.esp = ((unsigned long) ret->stack) + stack_size;
  64. ret->callee_regs.eip = (unsigned long) &coro_wrapper;
  65. printf("Creating coroutine with stack %x:%x and target %x\n", ret->stack, ret->stack + stack_size, target);
  66. return ret;
  67. }
  68. coro_t *coro_init(void (*target)(void*), void *ctx) {
  69. return coro_init_with_stack_size(target, ctx, 65536);
  70. }
  71. void coro_destroy(coro_t *coro) {
  72. _force_assert(!coro->runnable);
  73. free(coro->stack);
  74. free(coro);
  75. }