sjlj.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. note this was designed for UNIX systems. Based on ideas expressed in a paper by Ralf Engelschall.
  3. for SJLJ on other systems, one would want to rewrite springboard() and co_create() and hack the jmb_buf stack pointer.
  4. */
  5. #define LIBCO_C
  6. #include "libco.h"
  7. #include "settings.h"
  8. #define _BSD_SOURCE
  9. #define _XOPEN_SOURCE 500
  10. #include <stdlib.h>
  11. #include <signal.h>
  12. #include <setjmp.h>
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16. typedef struct {
  17. sigjmp_buf context;
  18. void (*coentry)(void);
  19. void* stack;
  20. } cothread_struct;
  21. static thread_local cothread_struct co_primary;
  22. static thread_local cothread_struct* creating;
  23. static thread_local cothread_struct* co_running = 0;
  24. static void springboard(int ignored) {
  25. if(sigsetjmp(creating->context, 0)) {
  26. co_running->coentry();
  27. }
  28. }
  29. cothread_t co_active() {
  30. if(!co_running) co_running = &co_primary;
  31. return (cothread_t)co_running;
  32. }
  33. cothread_t co_derive(void* memory, unsigned int size, void (*coentry)(void)) {
  34. if(!co_running) co_running = &co_primary;
  35. cothread_struct* thread = (cothread_struct*)memory;
  36. memory = (unsigned char*)memory + sizeof(cothread_struct);
  37. size -= sizeof(cothread_struct);
  38. if(thread) {
  39. struct sigaction handler;
  40. struct sigaction old_handler;
  41. stack_t stack;
  42. stack_t old_stack;
  43. thread->coentry = thread->stack = 0;
  44. stack.ss_flags = 0;
  45. stack.ss_size = size;
  46. thread->stack = stack.ss_sp = memory;
  47. if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
  48. handler.sa_handler = springboard;
  49. handler.sa_flags = SA_ONSTACK;
  50. sigemptyset(&handler.sa_mask);
  51. creating = thread;
  52. if(!sigaction(SIGUSR1, &handler, &old_handler)) {
  53. if(!raise(SIGUSR1)) {
  54. thread->coentry = coentry;
  55. }
  56. sigaltstack(&old_stack, 0);
  57. sigaction(SIGUSR1, &old_handler, 0);
  58. }
  59. }
  60. if(thread->coentry != coentry) {
  61. co_delete(thread);
  62. thread = 0;
  63. }
  64. }
  65. return (cothread_t)thread;
  66. }
  67. cothread_t co_create(unsigned int size, void (*coentry)(void)) {
  68. if(!co_running) co_running = &co_primary;
  69. cothread_struct* thread = (cothread_struct*)malloc(sizeof(cothread_struct));
  70. if(thread) {
  71. struct sigaction handler;
  72. struct sigaction old_handler;
  73. stack_t stack;
  74. stack_t old_stack;
  75. thread->coentry = thread->stack = 0;
  76. stack.ss_flags = 0;
  77. stack.ss_size = size;
  78. thread->stack = stack.ss_sp = malloc(size);
  79. if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
  80. handler.sa_handler = springboard;
  81. handler.sa_flags = SA_ONSTACK;
  82. sigemptyset(&handler.sa_mask);
  83. creating = thread;
  84. if(!sigaction(SIGUSR1, &handler, &old_handler)) {
  85. if(!raise(SIGUSR1)) {
  86. thread->coentry = coentry;
  87. }
  88. sigaltstack(&old_stack, 0);
  89. sigaction(SIGUSR1, &old_handler, 0);
  90. }
  91. }
  92. if(thread->coentry != coentry) {
  93. co_delete(thread);
  94. thread = 0;
  95. }
  96. }
  97. return (cothread_t)thread;
  98. }
  99. void co_delete(cothread_t cothread) {
  100. if(cothread) {
  101. if(((cothread_struct*)cothread)->stack) {
  102. free(((cothread_struct*)cothread)->stack);
  103. }
  104. free(cothread);
  105. }
  106. }
  107. void co_switch(cothread_t cothread) {
  108. if(!sigsetjmp(co_running->context, 0)) {
  109. co_running = (cothread_struct*)cothread;
  110. siglongjmp(co_running->context, 1);
  111. }
  112. }
  113. int co_serializable() {
  114. return 0;
  115. }
  116. #ifdef __cplusplus
  117. }
  118. #endif