1 #include "core/coroutine.hpp"
10 #if defined(__amd64__)
11 void trampoline_fn(void (*fn
)(void* arg
), void* arg
) __attribute__((sysv_abi
));
14 void trampoline_fn(void (*fn
)(void* arg
), void* arg
) __attribute__((stdcall));
16 #error "This CPU is not supported"
19 void trampoline_fn(void (*fn
)(void* arg
), void* arg
)
26 bool stacks_grow_down
= true;
27 void switch_stacks(void (*fn
)(void* arg
), void* arg
, void* new_esp
)
29 __asm__
__volatile__("movq %%rax,%%rsp; call *%%rdx" :: "D"(fn
), "S"(arg
), "a"(new_esp
), "d"(trampoline_fn
));
33 bool stacks_grow_down
= true;
34 void switch_stacks(void (*fn
)(void* arg
), void* arg
, void* new_esp
)
36 __asm__
__volatile__("movl %%eax,%%esp; pushl %%esi; push %%edi ; call *%%edx" :: "D"(fn
), "S"(arg
),
37 "a"(new_esp
), "d"(trampoline_fn
));
40 #error "This CPU is not supported"
43 jmp_buf main_saved_env
;
44 coroutine
* executing_coroutine
= NULL
;
47 coroutine::coroutine(void (*fn
)(void* arg
), void* arg
, size_t stacksize
)
50 if(executing_coroutine
) {
51 std::cerr
<< "FATAL: Coroutine create only allowed from main coroutine!" << std::endl
;
54 executing_coroutine
= this;
55 if(setjmp(main_saved_env
)) {
56 executing_coroutine
= NULL
;
59 stackblock
= new unsigned char[stacksize
];
60 unsigned char* esp
= stackblock
;
62 esp
= esp
+ stacksize
;
63 switch_stacks(fn
, arg
, esp
);
66 coroutine::~coroutine() throw()
69 std::cerr
<< "FATAL: Trying to delete a live coroutine!" << std::endl
;
75 void coroutine::resume()
77 if(executing_coroutine
) {
78 std::cerr
<< "FATAL: Coroutine resume only allowed from main coroutine!" << std::endl
;
83 executing_coroutine
= this;
84 if(setjmp(main_saved_env
)) {
85 executing_coroutine
= NULL
;
88 longjmp(saved_env
, 1);
91 void coroutine::yield()
93 if(!executing_coroutine
) {
94 std::cerr
<< "FATAL: Coroutine yield not allowed from main coroutine!" << std::endl
;
97 if(setjmp(executing_coroutine
->saved_env
))
99 longjmp(main_saved_env
, 1);
102 bool coroutine::is_dead()
107 void coroutine::cexit()
109 if(!executing_coroutine
) {
110 std::cerr
<< "FATAL: Main coroutine can't exit!" << std::endl
;
113 executing_coroutine
->dead
= true;
117 #ifdef TEST_COROUTINES
121 std::cout
<< "Print #1 from coroutine (" << arg
<< ")" << std::endl
;
123 std::cout
<< "Print #2 from coroutine (" << arg
<< ")" << std::endl
;
125 std::cout
<< "Print #3 from coroutine (" << arg
<< ")" << std::endl
;
131 coroutine
c(fn
, &x
, 8 * 1024 * 1024);
132 std::cout
<< "Back to main thread" << std::endl
;
133 std::cout
<< "Coroutine dead flag is " << c
.is_dead() << std::endl
;
135 std::cout
<< "Back to main thread" << std::endl
;
136 std::cout
<< "Coroutine dead flag is " << c
.is_dead() << std::endl
;
138 std::cout
<< "Back to main thread" << std::endl
;
139 std::cout
<< "Coroutine dead flag is " << c
.is_dead() << std::endl
;