207 #define MCO_API extern
211 #ifndef MCO_DEFAULT_STORAGE_SIZE
212 #define MCO_DEFAULT_STORAGE_SIZE 1024
316 #ifndef MCO_MIN_STACK_SIZE
317 #define MCO_MIN_STACK_SIZE 32768
321 #ifndef MCO_DEFAULT_STACK_SIZE
322 #define MCO_DEFAULT_STACK_SIZE 57344
326 #define MCO_MAGIC_NUMBER 0x7E3CB1A9
329 #if !defined(MCO_USE_UCONTEXT) && !defined(MCO_USE_FIBERS) && !defined(MCO_USE_ASM) && !defined(MCO_USE_ASYNCIFY)
331 #if (defined(__GNUC__) && defined(__x86_64__)) || (defined(_MSC_VER) && defined(_M_X64))
334 #define MCO_USE_FIBERS
336 #elif defined(__CYGWIN__)
337 #define MCO_USE_UCONTEXT
338 #elif defined(__EMSCRIPTEN__)
339 #define MCO_USE_FIBERS
340 #elif defined(__wasm__)
341 #define MCO_USE_ASYNCIFY
344 #if defined(__x86_64__) || \
345 defined(__i386) || defined(__i386__) || \
346 defined(__ARM_EABI__) || defined(__aarch64__) || \
350 #define MCO_USE_UCONTEXT
353 #define MCO_USE_UCONTEXT
358 #define _MCO_UNUSED(x) (void)(x)
360 #if !defined(MCO_NO_DEBUG) && !defined(NDEBUG) && !defined(MCO_DEBUG)
367 #define MCO_LOG(s) puts(s)
376 #define MCO_ASSERT(c) assert(c)
378 #define MCO_ASSERT(c)
382 #ifndef MCO_THREAD_LOCAL
383 #ifdef MCO_NO_MULTITHREAD
384 #define MCO_THREAD_LOCAL
387 #define MCO_THREAD_LOCAL thread_local
388 #elif __STDC_VERSION__ >= 201112 && !defined(__STDC_NO_THREADS__)
389 #define MCO_THREAD_LOCAL _Thread_local
390 #elif defined(_WIN32) && (defined(_MSC_VER) || defined(__ICL) || defined(__DMC__) || defined(__BORLANDC__))
391 #define MCO_THREAD_LOCAL __declspec(thread)
392 #elif defined(__GNUC__) || defined(__SUNPRO_C) || defined(__xlC__)
393 #define MCO_THREAD_LOCAL __thread
395 #define MCO_THREAD_LOCAL
396 #define MCO_NO_MULTITHREAD
401 #ifndef MCO_FORCE_INLINE
403 #define MCO_FORCE_INLINE __forceinline
404 #elif defined(__GNUC__)
405 #if defined(__STRICT_ANSI__)
406 #define MCO_FORCE_INLINE __inline__ __attribute__((always_inline))
408 #define MCO_FORCE_INLINE inline __attribute__((always_inline))
410 #elif defined(__BORLANDC__) || defined(__DMC__) || defined(__SC__) || defined(__WATCOMC__) || defined(__LCC__) || defined(__DECC)
411 #define MCO_FORCE_INLINE __inline
413 #define MCO_FORCE_INLINE
417 #ifndef MCO_NO_INLINE
419 #define MCO_NO_INLINE __attribute__((noinline))
420 #elif defined(_MSC_VER)
421 #define MCO_NO_INLINE __declspec(noinline)
423 #define MCO_NO_INLINE
427 #ifndef MCO_NO_DEFAULT_ALLOCATORS
430 #define MCO_MALLOC malloc
431 #define MCO_FREE free
433 static void* mco_malloc(
size_t size,
void* allocator_data) {
434 _MCO_UNUSED(allocator_data);
435 return MCO_MALLOC(
size);
437 static void mco_free(
void* ptr,
void* allocator_data) {
438 _MCO_UNUSED(allocator_data);
443 #if defined(__has_feature)
444 #if __has_feature(address_sanitizer)
445 #define _MCO_USE_ASAN
447 #if __has_feature(thread_sanitizer)
448 #define _MCO_USE_TSAN
451 #if defined(__SANITIZE_ADDRESS__)
452 #define _MCO_USE_ASAN
454 #if defined(__SANITIZE_THREAD__)
455 #define _MCO_USE_TSAN
458 void __sanitizer_start_switch_fiber(
void** fake_stack_save,
const void *bottom,
size_t size);
459 void __sanitizer_finish_switch_fiber(
void* fake_stack_save,
const void **bottom_old,
size_t *size_old);
462 void* __tsan_get_current_fiber(
void);
463 void* __tsan_create_fiber(
unsigned flags);
464 void __tsan_destroy_fiber(
void* fiber);
465 void __tsan_switch_to_fiber(
void* fiber,
unsigned flags);
471 static MCO_FORCE_INLINE
size_t _mco_align_forward(
size_t addr,
size_t align) {
472 return (addr + (align-1)) & ~(align-1);
476 static MCO_THREAD_LOCAL
mco_coro* mco_current_co = NULL;
478 static MCO_FORCE_INLINE
void _mco_prepare_jumpin(
mco_coro* co) {
481 MCO_ASSERT(co->
prev_co == NULL);
490 void* bottom_old = NULL;
492 __sanitizer_finish_switch_fiber(prev_co->
asan_prev_stack, (
const void**)&bottom_old, &size_old);
503 static MCO_FORCE_INLINE
void _mco_prepare_jumpout(
mco_coro* co) {
512 mco_current_co = prev_co;
514 void* bottom_old = NULL;
516 __sanitizer_finish_switch_fiber(co->
asan_prev_stack, (
const void**)&bottom_old, &size_old);
519 __sanitizer_start_switch_fiber(&prev_co->
asan_prev_stack, bottom_old, size_old);
525 __tsan_switch_to_fiber(tsan_prev_fiber, 0);
529 static void _mco_jumpin(
mco_coro* co);
530 static void _mco_jumpout(
mco_coro* co);
532 static MCO_NO_INLINE
void _mco_main(
mco_coro* co) {
540 #if defined(MCO_USE_UCONTEXT) || defined(MCO_USE_ASM)
572 #if defined(__x86_64__) || defined(_M_X64)
576 typedef struct _mco_ctxbuf {
577 void *rip, *rsp, *rbp, *rbx, *r12, *r13, *r14, *r15, *rdi, *rsi;
585 #if defined(__GNUC__)
586 #define _MCO_ASM_BLOB __attribute__((section(".text")))
587 #elif defined(_MSC_VER)
588 #define _MCO_ASM_BLOB __declspec(allocate(".text"))
589 #pragma section(".text")
592 _MCO_ASM_BLOB
static unsigned char _mco_wrap_main_code[] = {
596 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
599 _MCO_ASM_BLOB
static unsigned char _mco_switch_code[] = {
600 0x48, 0x8d, 0x05, 0x3e, 0x01, 0x00, 0x00,
602 0x48, 0x89, 0x61, 0x08,
603 0x48, 0x89, 0x69, 0x10,
604 0x48, 0x89, 0x59, 0x18,
605 0x4c, 0x89, 0x61, 0x20,
606 0x4c, 0x89, 0x69, 0x28,
607 0x4c, 0x89, 0x71, 0x30,
608 0x4c, 0x89, 0x79, 0x38,
609 0x48, 0x89, 0x79, 0x40,
610 0x48, 0x89, 0x71, 0x48,
611 0x0f, 0x11, 0x71, 0x50,
612 0x0f, 0x11, 0x79, 0x60,
613 0x44, 0x0f, 0x11, 0x41, 0x70,
614 0x44, 0x0f, 0x11, 0x89, 0x80, 0x00, 0x00, 0x00,
615 0x44, 0x0f, 0x11, 0x91, 0x90, 0x00, 0x00, 0x00,
616 0x44, 0x0f, 0x11, 0x99, 0xa0, 0x00, 0x00, 0x00,
617 0x44, 0x0f, 0x11, 0xa1, 0xb0, 0x00, 0x00, 0x00,
618 0x44, 0x0f, 0x11, 0xa9, 0xc0, 0x00, 0x00, 0x00,
619 0x44, 0x0f, 0x11, 0xb1, 0xd0, 0x00, 0x00, 0x00,
620 0x44, 0x0f, 0x11, 0xb9, 0xe0, 0x00, 0x00, 0x00,
621 0x65, 0x4c, 0x8b, 0x14, 0x25, 0x30, 0x00, 0x00, 0x00,
622 0x49, 0x8b, 0x42, 0x20,
623 0x48, 0x89, 0x81, 0xf0, 0x00, 0x00, 0x00,
624 0x49, 0x8b, 0x82, 0x78, 0x14, 0x00, 0x00,
625 0x48, 0x89, 0x81, 0xf8, 0x00, 0x00, 0x00,
626 0x49, 0x8b, 0x42, 0x10,
627 0x48, 0x89, 0x81, 0x00, 0x01, 0x00, 0x00,
628 0x49, 0x8b, 0x42, 0x08,
629 0x48, 0x89, 0x81, 0x08, 0x01, 0x00, 0x00,
630 0x48, 0x8b, 0x82, 0x08, 0x01, 0x00, 0x00,
631 0x49, 0x89, 0x42, 0x08,
632 0x48, 0x8b, 0x82, 0x00, 0x01, 0x00, 0x00,
633 0x49, 0x89, 0x42, 0x10,
634 0x48, 0x8b, 0x82, 0xf8, 0x00, 0x00, 0x00,
635 0x49, 0x89, 0x82, 0x78, 0x14, 0x00, 0x00,
636 0x48, 0x8b, 0x82, 0xf0, 0x00, 0x00, 0x00,
637 0x49, 0x89, 0x42, 0x20,
638 0x44, 0x0f, 0x10, 0xba, 0xe0, 0x00, 0x00, 0x00,
639 0x44, 0x0f, 0x10, 0xb2, 0xd0, 0x00, 0x00, 0x00,
640 0x44, 0x0f, 0x10, 0xaa, 0xc0, 0x00, 0x00, 0x00,
641 0x44, 0x0f, 0x10, 0xa2, 0xb0, 0x00, 0x00, 0x00,
642 0x44, 0x0f, 0x10, 0x9a, 0xa0, 0x00, 0x00, 0x00,
643 0x44, 0x0f, 0x10, 0x92, 0x90, 0x00, 0x00, 0x00,
644 0x44, 0x0f, 0x10, 0x8a, 0x80, 0x00, 0x00, 0x00,
645 0x44, 0x0f, 0x10, 0x42, 0x70,
646 0x0f, 0x10, 0x7a, 0x60,
647 0x0f, 0x10, 0x72, 0x50,
648 0x48, 0x8b, 0x72, 0x48,
649 0x48, 0x8b, 0x7a, 0x40,
650 0x4c, 0x8b, 0x7a, 0x38,
651 0x4c, 0x8b, 0x72, 0x30,
652 0x4c, 0x8b, 0x6a, 0x28,
653 0x4c, 0x8b, 0x62, 0x20,
654 0x48, 0x8b, 0x5a, 0x18,
655 0x48, 0x8b, 0x6a, 0x10,
656 0x48, 0x8b, 0x62, 0x08,
659 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
663 void (*_mco_wrap_main)(
void) = (
void(*)(
void))(
void*)_mco_wrap_main_code;
664 void (*_mco_switch)(_mco_ctxbuf* from, _mco_ctxbuf* to) = (
void(*)(_mco_ctxbuf* from, _mco_ctxbuf* to))(
void*)_mco_switch_code;
666 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
667 stack_size = stack_size - 32;
668 void** stack_high_ptr = (
void**)((
size_t)stack_base + stack_size -
sizeof(size_t));
669 stack_high_ptr[0] = (
void*)(0xdeaddeaddeaddead);
670 ctx->rip = (
void*)(_mco_wrap_main);
671 ctx->rsp = (
void*)(stack_high_ptr);
672 ctx->r12 = (
void*)(_mco_main);
673 ctx->r13 = (
void*)(co);
674 void* stack_top = (
void*)((
size_t)stack_base + stack_size);
675 ctx->stack_base = stack_top;
676 ctx->stack_limit = stack_base;
677 ctx->dealloc_stack = stack_base;
683 typedef struct _mco_ctxbuf {
684 void *rip, *rsp, *rbp, *rbx, *r12, *r13, *r14, *r15;
687 void _mco_wrap_main(
void);
688 int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to);
693 ".globl __mco_wrap_main\n"
696 ".globl _mco_wrap_main\n"
697 ".type _mco_wrap_main @function\n"
698 ".hidden _mco_wrap_main\n"
704 ".size _mco_wrap_main, .-_mco_wrap_main\n"
711 ".globl __mco_switch\n"
714 ".globl _mco_switch\n"
715 ".type _mco_switch @function\n"
716 ".hidden _mco_switch\n"
719 " leaq 0x3d(%rip), %rax\n"
720 " movq %rax, (%rdi)\n"
721 " movq %rsp, 8(%rdi)\n"
722 " movq %rbp, 16(%rdi)\n"
723 " movq %rbx, 24(%rdi)\n"
724 " movq %r12, 32(%rdi)\n"
725 " movq %r13, 40(%rdi)\n"
726 " movq %r14, 48(%rdi)\n"
727 " movq %r15, 56(%rdi)\n"
728 " movq 56(%rsi), %r15\n"
729 " movq 48(%rsi), %r14\n"
730 " movq 40(%rsi), %r13\n"
731 " movq 32(%rsi), %r12\n"
732 " movq 24(%rsi), %rbx\n"
733 " movq 16(%rsi), %rbp\n"
734 " movq 8(%rsi), %rsp\n"
738 ".size _mco_switch, .-_mco_switch\n"
742 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
743 stack_size = stack_size - 128;
744 void** stack_high_ptr = (
void**)((
size_t)stack_base + stack_size -
sizeof(size_t));
745 stack_high_ptr[0] = (
void*)(0xdeaddeaddeaddead);
746 ctx->rip = (
void*)(_mco_wrap_main);
747 ctx->rsp = (
void*)(stack_high_ptr);
748 ctx->r12 = (
void*)(_mco_main);
749 ctx->r13 = (
void*)(co);
755 #elif defined(__riscv)
757 typedef struct _mco_ctxbuf {
763 #if __riscv_flen == 64
765 #elif __riscv_flen == 32
771 void _mco_wrap_main(
void);
772 int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to);
776 ".globl _mco_wrap_main\n"
777 ".type _mco_wrap_main @function\n"
778 ".hidden _mco_wrap_main\n"
782 ".size _mco_wrap_main, .-_mco_wrap_main\n"
787 ".globl _mco_switch\n"
788 ".type _mco_switch @function\n"
789 ".hidden _mco_switch\n"
791 #
if __riscv_xlen == 64
802 " sd s10, 0x50(a0)\n"
803 " sd s11, 0x58(a0)\n"
808 #
if __riscv_flen == 64
809 " fsd fs0, 0x78(a0)\n"
810 " fsd fs1, 0x80(a0)\n"
811 " fsd fs2, 0x88(a0)\n"
812 " fsd fs3, 0x90(a0)\n"
813 " fsd fs4, 0x98(a0)\n"
814 " fsd fs5, 0xa0(a0)\n"
815 " fsd fs6, 0xa8(a0)\n"
816 " fsd fs7, 0xb0(a0)\n"
817 " fsd fs8, 0xb8(a0)\n"
818 " fsd fs9, 0xc0(a0)\n"
819 " fsd fs10, 0xc8(a0)\n"
820 " fsd fs11, 0xd0(a0)\n"
821 " fld fs0, 0x78(a1)\n"
822 " fld fs1, 0x80(a1)\n"
823 " fld fs2, 0x88(a1)\n"
824 " fld fs3, 0x90(a1)\n"
825 " fld fs4, 0x98(a1)\n"
826 " fld fs5, 0xa0(a1)\n"
827 " fld fs6, 0xa8(a1)\n"
828 " fld fs7, 0xb0(a1)\n"
829 " fld fs8, 0xb8(a1)\n"
830 " fld fs9, 0xc0(a1)\n"
831 " fld fs10, 0xc8(a1)\n"
832 " fld fs11, 0xd0(a1)\n"
834 #
error "Unsupported RISC-V FLEN"
847 " ld s10, 0x50(a1)\n"
848 " ld s11, 0x58(a1)\n"
853 #elif __riscv_xlen == 32
864 " sw s10, 0x28(a0)\n"
865 " sw s11, 0x2c(a0)\n"
870 #
if __riscv_flen == 64
871 " fsd fs0, 0x3c(a0)\n"
872 " fsd fs1, 0x44(a0)\n"
873 " fsd fs2, 0x4c(a0)\n"
874 " fsd fs3, 0x54(a0)\n"
875 " fsd fs4, 0x5c(a0)\n"
876 " fsd fs5, 0x64(a0)\n"
877 " fsd fs6, 0x6c(a0)\n"
878 " fsd fs7, 0x74(a0)\n"
879 " fsd fs8, 0x7c(a0)\n"
880 " fsd fs9, 0x84(a0)\n"
881 " fsd fs10, 0x8c(a0)\n"
882 " fsd fs11, 0x94(a0)\n"
883 " fld fs0, 0x3c(a1)\n"
884 " fld fs1, 0x44(a1)\n"
885 " fld fs2, 0x4c(a1)\n"
886 " fld fs3, 0x54(a1)\n"
887 " fld fs4, 0x5c(a1)\n"
888 " fld fs5, 0x64(a1)\n"
889 " fld fs6, 0x6c(a1)\n"
890 " fld fs7, 0x74(a1)\n"
891 " fld fs8, 0x7c(a1)\n"
892 " fld fs9, 0x84(a1)\n"
893 " fld fs10, 0x8c(a1)\n"
894 " fld fs11, 0x94(a1)\n"
895 #elif __riscv_flen == 32
896 " fsw fs0, 0x3c(a0)\n"
897 " fsw fs1, 0x40(a0)\n"
898 " fsw fs2, 0x44(a0)\n"
899 " fsw fs3, 0x48(a0)\n"
900 " fsw fs4, 0x4c(a0)\n"
901 " fsw fs5, 0x50(a0)\n"
902 " fsw fs6, 0x54(a0)\n"
903 " fsw fs7, 0x58(a0)\n"
904 " fsw fs8, 0x5c(a0)\n"
905 " fsw fs9, 0x60(a0)\n"
906 " fsw fs10, 0x64(a0)\n"
907 " fsw fs11, 0x68(a0)\n"
908 " flw fs0, 0x3c(a1)\n"
909 " flw fs1, 0x40(a1)\n"
910 " flw fs2, 0x44(a1)\n"
911 " flw fs3, 0x48(a1)\n"
912 " flw fs4, 0x4c(a1)\n"
913 " flw fs5, 0x50(a1)\n"
914 " flw fs6, 0x54(a1)\n"
915 " flw fs7, 0x58(a1)\n"
916 " flw fs8, 0x5c(a1)\n"
917 " flw fs9, 0x60(a1)\n"
918 " flw fs10, 0x64(a1)\n"
919 " flw fs11, 0x68(a1)\n"
921 #
error "Unsupported RISC-V FLEN"
934 " lw s10, 0x28(a1)\n"
935 " lw s11, 0x2c(a1)\n"
941 #
error "Unsupported RISC-V XLEN"
943 ".size _mco_switch, .-_mco_switch\n"
946 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
947 ctx->s[0] = (
void*)(co);
948 ctx->s[1] = (
void*)(_mco_main);
949 ctx->pc = (
void*)(_mco_wrap_main);
950 #if __riscv_xlen == 64
951 ctx->ra = (
void*)(0xdeaddeaddeaddead);
952 #elif __riscv_xlen == 32
953 ctx->ra = (
void*)(0xdeaddead);
955 ctx->sp = (
void*)((
size_t)stack_base + stack_size);
959 #elif defined(__i386) || defined(__i386__)
961 typedef struct _mco_ctxbuf {
962 void *eip, *esp, *ebp, *ebx, *esi, *edi;
965 void _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to);
972 ".globl _mco_switch\n"
973 ".type _mco_switch @function\n"
974 ".hidden _mco_switch\n"
980 " addl $(2f-1b), %ecx\n"
981 " movl 4(%esp), %eax\n"
982 " movl 8(%esp), %edx\n"
983 " movl %ecx, (%eax)\n"
984 " movl %esp, 4(%eax)\n"
985 " movl %ebp, 8(%eax)\n"
986 " movl %ebx, 12(%eax)\n"
987 " movl %esi, 16(%eax)\n"
988 " movl %edi, 20(%eax)\n"
989 " movl 20(%edx), %edi\n"
990 " movl 16(%edx), %esi\n"
991 " movl 12(%edx), %ebx\n"
992 " movl 8(%edx), %ebp\n"
993 " movl 4(%edx), %esp\n"
998 ".size _mco_switch, .-_mco_switch\n"
1002 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
1003 void** stack_high_ptr = (
void**)((
size_t)stack_base + stack_size - 16 - 1*
sizeof(size_t));
1004 stack_high_ptr[0] = (
void*)(0xdeaddead);
1005 stack_high_ptr[1] = (
void*)(co);
1006 ctx->eip = (
void*)(_mco_main);
1007 ctx->esp = (
void*)(stack_high_ptr);
1011 #elif defined(__ARM_EABI__)
1013 typedef struct _mco_ctxbuf {
1023 void _mco_wrap_main(
void);
1024 int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to);
1029 ".globl __mco_switch\n"
1032 ".globl _mco_switch\n"
1033 ".type _mco_switch #function\n"
1034 ".hidden _mco_switch\n"
1038 " vstmia r0!, {d8-d15}\n"
1040 " stmia r0, {r4-r11, lr}\n"
1041 " str sp, [r0, #9*4]\n"
1043 " vldmia r1!, {d8-d15}\n"
1045 " ldr sp, [r1, #9*4]\n"
1046 " ldmia r1, {r4-r11, pc}\n"
1048 ".size _mco_switch, .-_mco_switch\n"
1055 ".globl __mco_wrap_main\n"
1056 "__mco_wrap_main:\n"
1058 ".globl _mco_wrap_main\n"
1059 ".type _mco_wrap_main #function\n"
1060 ".hidden _mco_wrap_main\n"
1068 ".size _mco_wrap_main, .-_mco_wrap_main\n"
1072 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
1073 ctx->d[0] = (
void*)(co);
1074 ctx->d[1] = (
void*)(_mco_main);
1075 ctx->d[2] = (
void*)(0xdeaddead);
1076 ctx->lr = (
void*)(_mco_wrap_main);
1077 ctx->sp = (
void*)((
size_t)stack_base + stack_size);
1081 #elif defined(__aarch64__)
1083 typedef struct _mco_ctxbuf {
1090 void _mco_wrap_main(
void);
1091 int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to);
1096 ".globl __mco_switch\n"
1099 ".globl _mco_switch\n"
1100 ".type _mco_switch #function\n"
1101 ".hidden _mco_switch\n"
1107 " stp x19, x20, [x0, #(0*16)]\n"
1108 " stp x21, x22, [x0, #(1*16)]\n"
1109 " stp d8, d9, [x0, #(7*16)]\n"
1110 " stp x23, x24, [x0, #(2*16)]\n"
1111 " stp d10, d11, [x0, #(8*16)]\n"
1112 " stp x25, x26, [x0, #(3*16)]\n"
1113 " stp d12, d13, [x0, #(9*16)]\n"
1114 " stp x27, x28, [x0, #(4*16)]\n"
1115 " stp d14, d15, [x0, #(10*16)]\n"
1116 " stp x29, x30, [x0, #(5*16)]\n"
1117 " stp x10, x11, [x0, #(6*16)]\n"
1118 " ldp x19, x20, [x1, #(0*16)]\n"
1119 " ldp x21, x22, [x1, #(1*16)]\n"
1120 " ldp d8, d9, [x1, #(7*16)]\n"
1121 " ldp x23, x24, [x1, #(2*16)]\n"
1122 " ldp d10, d11, [x1, #(8*16)]\n"
1123 " ldp x25, x26, [x1, #(3*16)]\n"
1124 " ldp d12, d13, [x1, #(9*16)]\n"
1125 " ldp x27, x28, [x1, #(4*16)]\n"
1126 " ldp d14, d15, [x1, #(10*16)]\n"
1127 " ldp x29, x30, [x1, #(5*16)]\n"
1128 " ldp x10, x11, [x1, #(6*16)]\n"
1132 ".size _mco_switch, .-_mco_switch\n"
1139 ".globl __mco_wrap_main\n"
1140 "__mco_wrap_main:\n"
1142 ".globl _mco_wrap_main\n"
1143 ".type _mco_wrap_main #function\n"
1144 ".hidden _mco_wrap_main\n"
1151 ".size _mco_wrap_main, .-_mco_wrap_main\n"
1155 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
1156 ctx->x[0] = (
void*)(co);
1157 ctx->x[1] = (
void*)(_mco_main);
1158 ctx->x[2] = (
void*)(0xdeaddeaddeaddead);
1159 ctx->sp = (
void*)((
size_t)stack_base + stack_size);
1160 ctx->lr = (
void*)(_mco_wrap_main);
1166 #error "Unsupported architecture for assembly method."
1170 #elif defined(MCO_USE_UCONTEXT)
1172 #include <ucontext.h>
1174 typedef ucontext_t _mco_ctxbuf;
1176 #if defined(_LP64) || defined(__LP64__)
1177 static void _mco_wrap_main(
unsigned int lo,
unsigned int hi) {
1182 static void _mco_wrap_main(
unsigned int lo) {
1188 static MCO_FORCE_INLINE
void _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to) {
1189 int res = swapcontext(from, to);
1191 MCO_ASSERT(res == 0);
1194 static mco_result _mco_makectx(
mco_coro* co, _mco_ctxbuf* ctx,
void* stack_base,
size_t stack_size) {
1196 if(getcontext(ctx) != 0) {
1197 MCO_LOG(
"failed to get ucontext");
1200 ctx->uc_link = NULL;
1201 ctx->uc_stack.ss_sp = stack_base;
1202 ctx->uc_stack.ss_size = stack_size;
1203 unsigned int lo = (
unsigned int)((
size_t)co);
1204 #if defined(_LP64) || defined(__LP64__)
1205 unsigned int hi = (
unsigned int)(((
size_t)co)>>32);
1206 makecontext(ctx, (
void (*)(
void))_mco_wrap_main, 2, lo, hi);
1208 makecontext(ctx, (
void (*)(
void))_mco_wrap_main, 1, lo);
1215 #ifdef MCO_USE_VALGRIND
1216 #include <valgrind/valgrind.h>
1219 typedef struct _mco_context {
1220 #ifdef MCO_USE_VALGRIND
1221 unsigned int valgrind_stack_id;
1224 _mco_ctxbuf back_ctx;
1227 static void _mco_jumpin(
mco_coro* co) {
1228 _mco_context* context = (_mco_context*)co->
context;
1229 _mco_prepare_jumpin(co);
1230 _mco_switch(&context->back_ctx, &context->ctx);
1233 static void _mco_jumpout(
mco_coro* co) {
1234 _mco_context* context = (_mco_context*)co->
context;
1235 _mco_prepare_jumpout(co);
1236 _mco_switch(&context->ctx, &context->back_ctx);
1241 size_t co_addr = (size_t)co;
1242 size_t context_addr = _mco_align_forward(co_addr +
sizeof(
mco_coro), 16);
1243 size_t storage_addr = _mco_align_forward(context_addr +
sizeof(_mco_context), 16);
1244 size_t stack_addr = _mco_align_forward(storage_addr + desc->
storage_size, 16);
1246 _mco_context* context = (_mco_context*)context_addr;
1247 memset(context, 0,
sizeof(_mco_context));
1249 unsigned char* storage = (
unsigned char*)storage_addr;
1252 void *stack_base = (
void*)stack_addr;
1254 #ifdef MCO_ZERO_MEMORY
1255 memset(stack_base, 0, stack_size);
1258 mco_result res = _mco_makectx(co, &context->ctx, stack_base, stack_size);
1262 #ifdef MCO_USE_VALGRIND
1263 context->valgrind_stack_id = VALGRIND_STACK_REGISTER(stack_addr, stack_addr + stack_size);
1273 static void _mco_destroy_context(
mco_coro* co) {
1274 #ifdef MCO_USE_VALGRIND
1275 _mco_context* context = (_mco_context*)co->
context;
1276 if(context && context->valgrind_stack_id != 0) {
1277 VALGRIND_STACK_DEREGISTER(context->valgrind_stack_id);
1278 context->valgrind_stack_id = 0;
1285 static MCO_FORCE_INLINE
void _mco_init_desc_sizes(
mco_desc* desc,
size_t stack_size) {
1287 _mco_align_forward(
sizeof(_mco_context), 16) +
1297 #ifdef MCO_USE_FIBERS
1301 #ifndef _WIN32_WINNT
1302 #define _WIN32_WINNT 0x0400
1304 #ifndef WIN32_LEAN_AND_MEAN
1305 #define WIN32_LEAN_AND_MEAN
1307 #include <windows.h>
1309 typedef struct _mco_context {
1314 static void _mco_jumpin(
mco_coro* co) {
1315 void *cur_fib = GetCurrentFiber();
1316 if(!cur_fib || cur_fib == (
void*)0x1e00) {
1317 cur_fib = ConvertThreadToFiber(NULL);
1319 MCO_ASSERT(cur_fib != NULL);
1320 _mco_context* context = (_mco_context*)co->
context;
1321 context->back_fib = cur_fib;
1322 _mco_prepare_jumpin(co);
1323 SwitchToFiber(context->fib);
1326 static void CALLBACK _mco_wrap_main(
void* co) {
1330 static void _mco_jumpout(
mco_coro* co) {
1331 _mco_context* context = (_mco_context*)co->
context;
1332 void* back_fib = context->back_fib;
1333 MCO_ASSERT(back_fib != NULL);
1334 context->back_fib = NULL;
1335 _mco_prepare_jumpout(co);
1336 SwitchToFiber(back_fib);
1340 typedef struct _mco_fiber {
1345 void* stack_allocation;
1348 LPFIBER_START_ROUTINE start;
1354 size_t co_addr = (size_t)co;
1355 size_t context_addr = _mco_align_forward(co_addr +
sizeof(
mco_coro), 16);
1356 size_t storage_addr = _mco_align_forward(context_addr +
sizeof(_mco_context), 16);
1358 _mco_context* context = (_mco_context*)context_addr;
1359 memset(context, 0,
sizeof(_mco_context));
1361 unsigned char* storage = (
unsigned char*)storage_addr;
1364 _mco_fiber* fib = (_mco_fiber*)CreateFiberEx(desc->
stack_size, desc->
stack_size, FIBER_FLAG_FLOAT_SWITCH, _mco_wrap_main, co);
1366 MCO_LOG(
"failed to create fiber");
1378 static void _mco_destroy_context(
mco_coro* co) {
1379 _mco_context* context = (_mco_context*)co->
context;
1380 if(context && context->fib) {
1381 DeleteFiber(context->fib);
1382 context->fib = NULL;
1386 static MCO_FORCE_INLINE
void _mco_init_desc_sizes(
mco_desc* desc,
size_t stack_size) {
1388 _mco_align_forward(
sizeof(_mco_context), 16) +
1394 #elif defined(__EMSCRIPTEN__)
1396 #include <emscripten/fiber.h>
1398 #ifndef MCO_ASYNCFY_STACK_SIZE
1399 #define MCO_ASYNCFY_STACK_SIZE 16384
1402 typedef struct _mco_context {
1403 emscripten_fiber_t fib;
1404 emscripten_fiber_t* back_fib;
1407 static emscripten_fiber_t* running_fib = NULL;
1408 static unsigned char main_asyncify_stack[MCO_ASYNCFY_STACK_SIZE];
1409 static emscripten_fiber_t main_fib;
1411 static void _mco_wrap_main(
void* co) {
1415 static void _mco_jumpin(
mco_coro* co) {
1416 _mco_context* context = (_mco_context*)co->
context;
1417 emscripten_fiber_t* back_fib = running_fib;
1419 back_fib = &main_fib;
1420 emscripten_fiber_init_from_current_context(back_fib, main_asyncify_stack, MCO_ASYNCFY_STACK_SIZE);
1422 running_fib = &context->fib;
1423 context->back_fib = back_fib;
1424 _mco_prepare_jumpin(co);
1425 emscripten_fiber_swap(back_fib, &context->fib);
1428 static void _mco_jumpout(
mco_coro* co) {
1429 _mco_context* context = (_mco_context*)co->
context;
1430 running_fib = context->back_fib;
1431 _mco_prepare_jumpout(co);
1432 emscripten_fiber_swap(&context->fib, context->back_fib);
1436 if(emscripten_has_asyncify() != 1) {
1437 MCO_LOG(
"failed to create fiber because ASYNCIFY is not enabled");
1441 size_t co_addr = (size_t)co;
1442 size_t context_addr = _mco_align_forward(co_addr +
sizeof(
mco_coro), 16);
1443 size_t storage_addr = _mco_align_forward(context_addr +
sizeof(_mco_context), 16);
1444 size_t stack_addr = _mco_align_forward(storage_addr + desc->
storage_size, 16);
1445 size_t asyncify_stack_addr = _mco_align_forward(stack_addr + desc->
stack_size, 16);
1447 _mco_context* context = (_mco_context*)context_addr;
1448 memset(context, 0,
sizeof(_mco_context));
1450 unsigned char* storage = (
unsigned char*)storage_addr;
1453 void *stack_base = (
void*)stack_addr;
1454 size_t stack_size = asyncify_stack_addr - stack_addr;
1455 void *asyncify_stack_base = (
void*)asyncify_stack_addr;
1456 size_t asyncify_stack_size = co_addr + desc->
coro_size - asyncify_stack_addr;
1457 #ifdef MCO_ZERO_MEMORY
1458 memset(stack_base, 0, stack_size);
1459 memset(asyncify_stack_base, 0, asyncify_stack_size);
1462 emscripten_fiber_init(&context->fib, _mco_wrap_main, co, stack_base, stack_size, asyncify_stack_base, asyncify_stack_size);
1471 static void _mco_destroy_context(
mco_coro* co) {
1476 static MCO_FORCE_INLINE
void _mco_init_desc_sizes(
mco_desc* desc,
size_t stack_size) {
1478 _mco_align_forward(
sizeof(_mco_context), 16) +
1480 _mco_align_forward(stack_size, 16) +
1481 _mco_align_forward(MCO_ASYNCFY_STACK_SIZE, 16) +
1488 #error "Unsupported architecture for fibers method."
1496 #ifdef MCO_USE_ASYNCIFY
1498 typedef struct _asyncify_stack_region {
1501 } _asyncify_stack_region;
1503 typedef struct _mco_context {
1505 _asyncify_stack_region stack_region;
1508 __attribute__((import_module(
"asyncify"), import_name(
"start_unwind")))
void _asyncify_start_unwind(
void*);
1509 __attribute__((import_module("asyncify"), import_name("stop_unwind")))
void _asyncify_stop_unwind();
1510 __attribute__((import_module("asyncify"), import_name("start_rewind")))
void _asyncify_start_rewind(
void*);
1511 __attribute__((import_module("asyncify"), import_name("stop_rewind")))
void _asyncify_stop_rewind();
1513 MCO_NO_INLINE
void _mco_jumpin(
mco_coro* co) {
1514 _mco_context* context = (_mco_context*)co->context;
1515 _mco_prepare_jumpin(co);
1516 if(context->rewind_id > 0) {
1517 _asyncify_start_rewind(&context->stack_region);
1520 _asyncify_stop_unwind();
1523 static MCO_NO_INLINE
void _mco_finish_jumpout(
mco_coro* co,
volatile int rewind_id) {
1524 _mco_context* context = (_mco_context*)co->
context;
1525 int next_rewind_id = context->rewind_id + 1;
1526 if(rewind_id == next_rewind_id) {
1527 _mco_prepare_jumpout(co);
1528 context->rewind_id = next_rewind_id;
1529 _asyncify_start_unwind(&context->stack_region);
1530 }
else if(rewind_id == context->rewind_id) {
1531 _asyncify_stop_rewind();
1536 MCO_NO_INLINE
void _mco_jumpout(
mco_coro* co) {
1537 _mco_context* context = (_mco_context*)co->
context;
1543 volatile int rewind_id = context->rewind_id + 1;
1544 _mco_finish_jumpout(co, rewind_id);
1549 size_t co_addr = (size_t)co;
1550 size_t context_addr = _mco_align_forward(co_addr +
sizeof(
mco_coro), 16);
1551 size_t storage_addr = _mco_align_forward(context_addr +
sizeof(_mco_context), 16);
1552 size_t stack_addr = _mco_align_forward(storage_addr + desc->
storage_size, 16);
1554 _mco_context* context = (_mco_context*)context_addr;
1555 memset(context, 0,
sizeof(_mco_context));
1557 unsigned char* storage = (
unsigned char*)storage_addr;
1560 void *stack_base = (
void*)stack_addr;
1562 #ifdef MCO_ZERO_MEMORY
1563 memset(stack_base, 0, stack_size);
1565 context->stack_region.start = stack_base;
1566 context->stack_region.limit = (
void*)((
size_t)stack_base + stack_size);
1575 static void _mco_destroy_context(
mco_coro* co) {
1580 static MCO_FORCE_INLINE
void _mco_init_desc_sizes(
mco_desc* desc,
size_t stack_size) {
1582 _mco_align_forward(
sizeof(_mco_context), 16) +
1584 _mco_align_forward(stack_size, 16) +
1594 if(stack_size != 0) {
1596 if(stack_size < MCO_MIN_STACK_SIZE) {
1597 stack_size = MCO_MIN_STACK_SIZE;
1600 stack_size = MCO_DEFAULT_STACK_SIZE;
1602 stack_size = _mco_align_forward(stack_size, 16);
1604 memset(&desc, 0,
sizeof(
mco_desc));
1605 #ifndef MCO_NO_DEFAULT_ALLOCATORS
1612 _mco_init_desc_sizes(&desc, stack_size);
1618 MCO_LOG(
"coroutine description is NULL");
1622 MCO_LOG(
"coroutine function in invalid");
1626 MCO_LOG(
"coroutine stack size is too small");
1630 MCO_LOG(
"coroutine size is invalid");
1638 MCO_LOG(
"attempt to initialize an invalid coroutine");
1647 res = _mco_create_context(co, desc);
1655 #ifdef _MCO_USE_TSAN
1664 MCO_LOG(
"attempt to uninitialize an invalid coroutine");
1669 MCO_LOG(
"attempt to uninitialize a coroutine that is not dead or suspended");
1674 #ifdef _MCO_USE_TSAN
1680 _mco_destroy_context(co);
1687 MCO_LOG(
"coroutine output pointer is NULL");
1692 MCO_LOG(
"coroutine allocator description is not set");
1698 MCO_LOG(
"coroutine allocation failed");
1715 MCO_LOG(
"attempt to destroy an invalid coroutine");
1724 MCO_LOG(
"attempt destroy a coroutine that has no free callback");
1733 MCO_LOG(
"attempt to resume an invalid coroutine");
1737 MCO_LOG(
"attempt to resume a coroutine that is not suspended");
1747 MCO_LOG(
"attempt to yield an invalid coroutine");
1750 #ifdef MCO_USE_ASYNCIFY
1754 volatile size_t dummy;
1755 size_t stack_addr = (size_t)&dummy;
1757 size_t stack_max = stack_min + co->
stack_size;
1758 if(co->
magic_number != MCO_MAGIC_NUMBER || stack_addr < stack_min || stack_addr > stack_max) {
1759 MCO_LOG(
"coroutine stack overflow, try increasing the stack size");
1764 MCO_LOG(
"attempt to yield a coroutine that is not running");
1788 MCO_LOG(
"attempt to use an invalid coroutine");
1790 }
else if(len > 0) {
1793 MCO_LOG(
"attempt to push too many bytes into coroutine storage");
1797 MCO_LOG(
"attempt push a null pointer into coroutine storage");
1808 MCO_LOG(
"attempt to use an invalid coroutine");
1810 }
else if(len > 0) {
1812 MCO_LOG(
"attempt to pop too many bytes from coroutine storage");
1817 memcpy(dest, &co->
storage[bytes_stored], len);
1820 #ifdef MCO_ZERO_MEMORY
1822 memset(&co->
storage[bytes_stored], 0, len);
1830 MCO_LOG(
"attempt to use an invalid coroutine");
1832 }
else if(len > 0) {
1834 MCO_LOG(
"attempt to peek too many bytes from coroutine storage");
1838 MCO_LOG(
"attempt peek into a null pointer");
1860 #ifdef MCO_NO_MULTITHREAD
1862 return mco_current_co;
1865 static MCO_NO_INLINE
mco_coro* _mco_running(
void) {
1866 return mco_current_co;
1874 mco_coro* (*
volatile func)(
void) = _mco_running;
1884 return "Generic error";
1886 return "Invalid pointer";
1888 return "Invalid coroutine";
1890 return "Coroutine not suspended";
1892 return "Coroutine not running";
1894 return "Make context error";
1896 return "Switch context error";
1898 return "Not enough space";
1900 return "Out of memory";
1902 return "Invalid arguments";
1904 return "Invalid operation";
1906 return "Stack overflow";
1908 return "Unknown error";