ucontext.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /*
  2. WARNING: the overhead of POSIX ucontext is very high,
  3. assembly versions of libco or libco_sjlj should be much faster
  4. this library only exists for two reasons:
  5. 1: as an initial test for the viability of a ucontext implementation
  6. 2: to demonstrate the power and speed of libco over existing implementations,
  7. such as pth (which defaults to wrapping ucontext on unix targets)
  8. use this library only as a *last resort*
  9. */
  10. #define LIBCO_C
  11. #include "libco.h"
  12. #include "settings.h"
  13. #define _BSD_SOURCE
  14. #define _XOPEN_SOURCE 500
  15. #include <stdlib.h>
  16. #include <ucontext.h>
  17. #ifdef __cplusplus
  18. extern "C" {
  19. #endif
  20. static thread_local ucontext_t co_primary;
  21. static thread_local ucontext_t* co_running = 0;
  22. cothread_t co_active() {
  23. if(!co_running) co_running = &co_primary;
  24. return (cothread_t)co_running;
  25. }
  26. cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void)) {
  27. if(!co_running) co_running = &co_primary;
  28. ucontext_t* thread = (ucontext_t*)memory;
  29. memory = (unsigned char*)memory + sizeof(ucontext_t);
  30. heapsize -= sizeof(ucontext_t);
  31. if(thread) {
  32. if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = memory)) {
  33. thread->uc_link = co_running;
  34. thread->uc_stack.ss_size = heapsize;
  35. makecontext(thread, coentry, 0);
  36. } else {
  37. thread = 0;
  38. }
  39. }
  40. return (cothread_t)thread;
  41. }
  42. cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
  43. if(!co_running) co_running = &co_primary;
  44. ucontext_t* thread = (ucontext_t*)malloc(sizeof(ucontext_t));
  45. if(thread) {
  46. if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {
  47. thread->uc_link = co_running;
  48. thread->uc_stack.ss_size = heapsize;
  49. makecontext(thread, coentry, 0);
  50. } else {
  51. co_delete((cothread_t)thread);
  52. thread = 0;
  53. }
  54. }
  55. return (cothread_t)thread;
  56. }
  57. void co_delete(cothread_t cothread) {
  58. if(cothread) {
  59. if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }
  60. free(cothread);
  61. }
  62. }
  63. void co_switch(cothread_t cothread) {
  64. ucontext_t* old_thread = co_running;
  65. co_running = (ucontext_t*)cothread;
  66. swapcontext(old_thread, co_running);
  67. }
  68. int co_serializable() {
  69. return 0;
  70. }
  71. #ifdef __cplusplus
  72. }
  73. #endif