12#include <asyncpp/detail/sanitizers.h> 
   15#ifndef ASYNCPP_FIBER_KEYWORDS 
   16#define ASYNCPP_FIBER_KEYWORDS 1 
   24#ifndef ASYNCPP_FIBER_USE_UCONTEXT 
   25#define ASYNCPP_FIBER_USE_UCONTEXT 0 
   28#if ASYNCPP_FIBER_USE_UCONTEXT 
   32#if !defined(MAP_ANON) && defined(__APPLE__) 
   33#define MAP_ANON 0x1000 
   36namespace asyncpp::detail {
 
   37    struct stack_context {
 
   44    inline bool fiber_allocate_stack(stack_context& ctx, 
size_t size) 
noexcept {
 
   45        static size_t pagesize = sysconf(_SC_PAGESIZE);
 
   48        const auto page_count = (size + pagesize - 1) / pagesize;
 
   49        size = page_count * pagesize;
 
   50        const auto alloc_size = size + pagesize * 2;
 
   53            ::mmap(
nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
 
   54#elif defined(MAP_ANON) 
   55        void* 
const stack = ::mmap(
nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 
   57        void* 
const stack = ::mmap(
nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 
   59        if (stack == MAP_FAILED) 
return false;
 
   62        [[maybe_unused]] 
auto res = ::mprotect(stack, pagesize, PROT_NONE);
 
   64        res = ::mprotect(
static_cast<std::byte*
>(stack) + size + pagesize, pagesize, PROT_NONE);
 
   67        ctx.stack = 
static_cast<std::byte*
>(stack) + size + pagesize;
 
   68        ctx.stack_size = size;
 
   69        ctx.mmap_base = stack;
 
   70        ctx.mmap_size = alloc_size;
 
   74    inline bool fiber_deallocate_stack(stack_context& ctx) {
 
   75        if (ctx.mmap_base == 
nullptr) 
return true;
 
   77        auto res = ::munmap(ctx.mmap_base, ctx.mmap_size);
 
   81#if ASYNCPP_FIBER_USE_UCONTEXT 
   82    struct fiber_context {
 
   88    inline bool fiber_makecontext(fiber_context* ctx, 
const stack_context& stack, 
void (*fn)(
void* arg), 
void* arg) {
 
   89        static void (*
const wrapper)(uint32_t, uint32_t, uint32_t, uint32_t) = [](uint32_t fn_hi, uint32_t fn_low,
 
   90                                                                                  uint32_t arg_hi, uint32_t arg_low) {
 
   91            uintptr_t fn = (
static_cast<uintptr_t
>(fn_hi) << 32) | 
static_cast<uintptr_t
>(fn_low);
 
   92            uintptr_t arg = (
static_cast<uintptr_t
>(arg_hi) << 32) | 
static_cast<uintptr_t
>(arg_low);
 
   93            reinterpret_cast<void (*)(
void*)
>(fn)(
reinterpret_cast<void*
>(arg));
 
   95        getcontext(&ctx->context);
 
   96        ctx->context.uc_link = 
nullptr;
 
   97        ctx->context.uc_stack.ss_sp = 
reinterpret_cast<decltype(ctx-
>context.uc_stack.ss_sp)>(
 
   98            reinterpret_cast<uintptr_t
>(stack.stack) - stack.stack_size);
 
   99        ctx->context.uc_stack.ss_size = stack.stack_size;
 
  100        makecontext(&ctx->context, 
reinterpret_cast<void (*)()
>(wrapper), 4,
 
  101                    (
reinterpret_cast<uintptr_t
>(fn) >> 32) & 0xffffffff, 
reinterpret_cast<uintptr_t
>(fn) & 0xffffffff,
 
  102                    (
reinterpret_cast<uintptr_t
>(arg) >> 32) & 0xffffffff,
 
  103                    reinterpret_cast<uintptr_t
>(arg) & 0xffffffff);
 
  107    inline bool fiber_swapcontext(fiber_context* out, fiber_context* in) {
 
  108        swapcontext(&out->context, &in->context);
 
  112    inline bool fiber_destroy_context(fiber_context* ctx) {
 
  113        memset(ctx, 0, 
sizeof(fiber_context));
 
  117    struct fiber_context {
 
  123    inline bool fiber_makecontext(fiber_context* ctx, 
const stack_context& stack, 
void (*entry_fn)(
void* arg),
 
  125        ctx->stack = stack.stack;
 
  126        ctx->stack_size = stack.stack_size;
 
  130        auto sp = 
reinterpret_cast<uintptr_t*
>(
reinterpret_cast<uintptr_t
>(stack.stack) & 
static_cast<uintptr_t
>(~15L));
 
  139            uintptr_t stack_guard;
 
  149            uintptr_t : 
sizeof(uintptr_t) * 8;
 
  152        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 10);
 
  153        sp -= 
sizeof(stack_frame) / 
sizeof(uintptr_t);
 
  154        memset(sp, 0, 
reinterpret_cast<uintptr_t
>(stack.stack) - 
reinterpret_cast<uintptr_t
>(sp));
 
  155        auto frame = 
reinterpret_cast<stack_frame*
>(sp);
 
  156        frame->ret_addr = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  157        frame->param = 
reinterpret_cast<uintptr_t
>(arg);
 
  158        assert((
reinterpret_cast<uintptr_t
>(sp) % 16) == 0xc);
 
  159#elif defined(__x86_64__) 
  167            uintptr_t stack_guard;
 
  180        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 10);
 
  181        sp -= 
sizeof(stack_frame) / 
sizeof(uintptr_t);
 
  182        memset(sp, 0, 
reinterpret_cast<uintptr_t
>(stack.stack) - 
reinterpret_cast<uintptr_t
>(sp));
 
  183        auto frame = 
reinterpret_cast<stack_frame*
>(sp);
 
  184        frame->ret_addr = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  185        frame->param = 
reinterpret_cast<uintptr_t
>(arg);
 
  186#elif defined(__arm__) 
  190#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) 
  191            uintptr_t d8_d15[16];
 
  212#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) 
  213        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 28);
 
  215        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 11);
 
  217        sp -= 
sizeof(stack_frame) / 
sizeof(uintptr_t);
 
  218        memset(sp, 0, 
reinterpret_cast<uintptr_t
>(stack.stack) - 
reinterpret_cast<uintptr_t
>(sp));
 
  219        auto frame = 
reinterpret_cast<stack_frame*
>(sp);
 
  220        frame->ret_addr = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  221        frame->param = 
reinterpret_cast<uintptr_t
>(arg);
 
  222#elif defined(__arm64__) || defined(__aarch64__) 
  227            uintptr_t x19_x29[11];
 
  238        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 22);
 
  239        sp -= 
sizeof(stack_frame) / 
sizeof(uintptr_t);
 
  240        memset(sp, 0, 
reinterpret_cast<uintptr_t
>(stack.stack) - 
reinterpret_cast<uintptr_t
>(sp));
 
  241        auto frame = 
reinterpret_cast<stack_frame*
>(sp);
 
  242        frame->ret_addr = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  243        frame->param = 
reinterpret_cast<uintptr_t
>(arg);
 
  244#elif defined(__s390x__) 
  259        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 18);
 
  260        sp -= 
sizeof(stack_frame) / 
sizeof(uintptr_t);
 
  261        memset(sp, 0, 
reinterpret_cast<uintptr_t
>(stack.stack) - 
reinterpret_cast<uintptr_t
>(sp));
 
  262        auto frame = 
reinterpret_cast<stack_frame*
>(sp);
 
  263        frame->ret_addr = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  264        frame->param = 
reinterpret_cast<uintptr_t
>(arg);
 
  265#elif defined(__powerpc64__) 
  274            uintptr_t r14_31[18];
 
  275            uintptr_t fr14_31[18];
 
  280        static_assert(
sizeof(stack_frame) == 
sizeof(uintptr_t) * 42);
 
  281        sp -= 
sizeof(stack_frame) / 
sizeof(uintptr_t);
 
  282        memset(sp, 0, 
reinterpret_cast<uintptr_t
>(stack.stack) - 
reinterpret_cast<uintptr_t
>(sp));
 
  283        auto frame = 
reinterpret_cast<stack_frame*
>(sp);
 
  287        frame->r12 = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  288        frame->ret_addr = 
reinterpret_cast<uintptr_t
>(entry_fn);
 
  289        frame->param = 
reinterpret_cast<uintptr_t
>(arg);
 
  291#error "Unsupported architecture." 
  293        ctx->current_sp = sp;
 
  297    __attribute__((naked, noinline)) 
inline void fiber_swap_stack(
void** current_pointer_out, 
void* dest_pointer) {
 
  301        asm(
"leal -0x1c(%esp), %esp\n" 
  305#ifdef SAVE_TLS_STACK_PROTECTOR 
  306            "movl  %gs:0x14, %ecx\n"   
  307            "movl  %ecx, 0x8(%esp)\n"  
  309            "movl  %edi, 0xc(%esp)\n"   
  310            "movl  %esi, 0x10(%esp)\n"  
  311            "movl  %ebx, 0x14(%esp)\n"  
  312            "movl  %ebp, 0x18(%esp)\n"  
  314            "movl 0x20(%esp), %ecx\n"  
  315            "movl %esp, (%ecx)\n"      
  317            "mov 0x24(%esp), %esi\n"  
  322#ifdef SAVE_TLS_STACK_PROTECTOR 
  323            "movl  0x8(%esp), %edx\n"  
  324            "movl  %edx, %gs:0x14\n"   
  326            "movl 0xc(%esp), %edi\n"   
  327            "movl 0x10(%esp), %esi\n"  
  328            "movl 0x14(%esp), %ebx\n"  
  329            "movl 0x18(%esp), %ebp\n"  
  331            "leal  0x1c(%esp), %esp\n"  
  334#elif defined(__x86_64__) 
  335#if !(defined(__LP64__) || defined(__LLP64__)) 
  337#error "Non-native pointer size." 
  341        asm(
"leaq -0x48(%rsp), %rsp\n" 
  345#ifdef SAVE_TLS_STACK_PROTECTOR 
  346            "movq  %fs:0x28, %rcx\n"   
  347            "movq  %rcx, 0x8(%rsp)\n"  
  349            "movq  %r12, 0x10(%rsp)\n"  
  350            "movq  %r13, 0x18(%rsp)\n"  
  351            "movq  %r14, 0x20(%rsp)\n"  
  352            "movq  %r15, 0x28(%rsp)\n"  
  353            "movq  %rbx, 0x30(%rsp)\n"  
  354            "movq  %rbp, 0x38(%rsp)\n"  
  356            "movq %rsp, (%rdi)\n" 
  362#ifdef SAVE_TLS_STACK_PROTECTOR 
  363            "movq 0x8(%rsp), %rcx\n"  
  364            "movq %rcx, %fs:28\n" 
  367            "movq  0x10(%rsp), %r12\n" 
  368            "movq  0x18(%rsp), %r13\n" 
  369            "movq  0x20(%rsp), %r14\n" 
  370            "movq  0x28(%rsp), %r15\n" 
  371            "movq  0x30(%rsp), %rbx\n" 
  372            "movq  0x38(%rsp), %rbp\n" 
  373            "movq  0x40(%rsp), %rdi\n" 
  375            "leaq  0x48(%rsp), %rsp\n" 
  378#elif defined(__arm__) 
  386#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) 
  388            "vstmia sp, {d8-d15}\n" 
  396#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) 
  397            "vldmia  sp, {d8-d15}\n" 
  407#elif defined(__arm64__) || defined(__aarch64__) 
  412            "sub sp, sp, #0xb0\n" 
  413            "stp d8,  d9,  [sp, #0x00]\n" 
  414            "stp d10, d11, [sp, #0x10]\n" 
  415            "stp d12, d13, [sp, #0x20]\n" 
  416            "stp d14, d15, [sp, #0x30]\n" 
  417            "stp x19, x20, [sp, #0x40]\n" 
  418            "stp x21, x22, [sp, #0x50]\n" 
  419            "stp x23, x24, [sp, #0x60]\n" 
  420            "stp x25, x26, [sp, #0x70]\n" 
  421            "stp x27, x28, [sp, #0x80]\n" 
  422            "stp x29, x30, [sp, #0x90]\n" 
  429            "ldp d8,  d9,  [sp, #0x00]\n" 
  430            "ldp d10, d11, [sp, #0x10]\n" 
  431            "ldp d12, d13, [sp, #0x20]\n" 
  432            "ldp d14, d15, [sp, #0x30]\n" 
  433            "ldp x19, x20, [sp, #0x40]\n" 
  434            "ldp x21, x22, [sp, #0x50]\n" 
  435            "ldp x23, x24, [sp, #0x60]\n" 
  436            "ldp x25, x26, [sp, #0x70]\n" 
  437            "ldp x27, x28, [sp, #0x80]\n" 
  438            "ldp x29, x30, [sp, #0x90]\n" 
  439            "ldr x0,       [sp, #0xa0]\n" 
  440            "add sp, sp, #0xb0\n" 
  443#elif defined(__s390x__) 
  448            "aghi %r15, -(8*18)\n" 
  450            "stmg %r6, %r14, 64(%r15)\n" 
  451            "std %f8, (8*0)(%r15)\n" 
  452            "std %f9, (8*1)(%r15)\n" 
  453            "std %f10, (8*2)(%r15)\n" 
  454            "std %f11, (8*3)(%r15)\n" 
  455            "std %f12, (8*4)(%r15)\n" 
  456            "std %f13, (8*5)(%r15)\n" 
  457            "std %f14, (8*6)(%r15)\n" 
  458            "std %f15, (8*7)(%r15)\n" 
  464            "lmg %r6, %r14, (8*8)(%r15)\n" 
  465            "ld %f8, (8*0)(%r15)\n" 
  466            "ld %f9, (8*1)(%r15)\n" 
  467            "ld %f10, (8*2)(%r15)\n" 
  468            "ld %f11, (8*3)(%r15)\n" 
  469            "ld %f12, (8*4)(%r15)\n" 
  470            "ld %f13, (8*5)(%r15)\n" 
  471            "ld %f14, (8*6)(%r15)\n" 
  472            "ld %f15, (8*7)(%r15)\n" 
  473            "lg %r2, (8*17)(%r15)\n" 
  475            "aghi %r15, (8*18)\n" 
  478#elif defined(__powerpc64__) 
  481        asm(
"addis   %r2, %r12, .TOC.-fiber_swap_stack@ha\n" 
  482            "addi    %r2, %r2, .TOC.-fiber_swap_stack@l\n" 
  483            ".localentry fiber_swap_stack, . - fiber_swap_stack\n" 
  484            "addi %r1, %r1, -(42*8)\n" 
  487            "std %r2, (8*0)(%r1)\n" 
  488            "std %r3, (8*1)(%r1)\n" 
  489            "std %r12, (8*2)(%r1)\n" 
  490            "std %r14, (8*3)(%r1)\n" 
  491            "std %r15, (8*4)(%r1)\n" 
  492            "std %r16, (8*5)(%r1)\n" 
  493            "std %r17, (8*6)(%r1)\n" 
  494            "std %r18, (8*7)(%r1)\n" 
  495            "std %r19, (8*8)(%r1)\n" 
  496            "std %r20, (8*9)(%r1)\n" 
  497            "std %r21, (8*10)(%r1)\n" 
  498            "std %r22, (8*11)(%r1)\n" 
  499            "std %r23, (8*12)(%r1)\n" 
  500            "std %r24, (8*13)(%r1)\n" 
  501            "std %r25, (8*14)(%r1)\n" 
  502            "std %r26, (8*15)(%r1)\n" 
  503            "std %r27, (8*16)(%r1)\n" 
  504            "std %r28, (8*17)(%r1)\n" 
  505            "std %r29, (8*18)(%r1)\n" 
  506            "std %r30, (8*19)(%r1)\n" 
  507            "std %r31, (8*20)(%r1)\n" 
  508            "stfd %f14, (8*21)(%r1)\n" 
  509            "stfd %f15, (8*22)(%r1)\n" 
  510            "stfd %f16, (8*23)(%r1)\n" 
  511            "stfd %f17, (8*24)(%r1)\n" 
  512            "stfd %f18, (8*25)(%r1)\n" 
  513            "stfd %f19, (8*26)(%r1)\n" 
  514            "stfd %f20, (8*27)(%r1)\n" 
  515            "stfd %f21, (8*28)(%r1)\n" 
  516            "stfd %f22, (8*29)(%r1)\n" 
  517            "stfd %f23, (8*30)(%r1)\n" 
  518            "stfd %f24, (8*31)(%r1)\n" 
  519            "stfd %f25, (8*32)(%r1)\n" 
  520            "stfd %f26, (8*33)(%r1)\n" 
  521            "stfd %f27, (8*34)(%r1)\n" 
  522            "stfd %f28, (8*35)(%r1)\n" 
  523            "stfd %f29, (8*36)(%r1)\n" 
  524            "stfd %f30, (8*37)(%r1)\n" 
  525            "stfd %f31, (8*38)(%r1)\n" 
  527            "std %r0, (8*39)(%r1)\n" 
  529            "std %r0, (8*40)(%r1)\n" 
  530            "std %r0, (8*41)(%r1)\n" 
  536            "ld %r2, (8*0)(%r1)\n" 
  537            "ld %r3, (8*1)(%r1)\n" 
  538            "ld %r12, (8*2)(%r1)\n" 
  539            "ld %r14, (8*3)(%r1)\n" 
  540            "ld %r15, (8*4)(%r1)\n" 
  541            "ld %r16, (8*5)(%r1)\n" 
  542            "ld %r17, (8*6)(%r1)\n" 
  543            "ld %r18, (8*7)(%r1)\n" 
  544            "ld %r19, (8*8)(%r1)\n" 
  545            "ld %r20, (8*9)(%r1)\n" 
  546            "ld %r21, (8*10)(%r1)\n" 
  547            "ld %r22, (8*11)(%r1)\n" 
  548            "ld %r23, (8*12)(%r1)\n" 
  549            "ld %r24, (8*13)(%r1)\n" 
  550            "ld %r25, (8*14)(%r1)\n" 
  551            "ld %r26, (8*15)(%r1)\n" 
  552            "ld %r27, (8*16)(%r1)\n" 
  553            "ld %r28, (8*17)(%r1)\n" 
  554            "ld %r29, (8*18)(%r1)\n" 
  555            "ld %r30, (8*19)(%r1)\n" 
  556            "ld %r31, (8*20)(%r1)\n" 
  557            "lfd %f14,(8*21)(%r1)\n" 
  558            "lfd %f15,(8*22)(%r1)\n" 
  559            "lfd %f16,(8*23)(%r1)\n" 
  560            "lfd %f17,(8*24)(%r1)\n" 
  561            "lfd %f18,(8*25)(%r1)\n" 
  562            "lfd %f19,(8*26)(%r1)\n" 
  563            "lfd %f20,(8*27)(%r1)\n" 
  564            "lfd %f21,(8*28)(%r1)\n" 
  565            "lfd %f22,(8*29)(%r1)\n" 
  566            "lfd %f23,(8*30)(%r1)\n" 
  567            "lfd %f24,(8*31)(%r1)\n" 
  568            "lfd %f25,(8*32)(%r1)\n" 
  569            "lfd %f26,(8*33)(%r1)\n" 
  570            "lfd %f27,(8*34)(%r1)\n" 
  571            "lfd %f28,(8*35)(%r1)\n" 
  572            "lfd %f29,(8*36)(%r1)\n" 
  573            "lfd %f30,(8*37)(%r1)\n" 
  574            "lfd %f31,(8*38)(%r1)\n" 
  575            "ld %r0, (8*39)(%r1)\n" 
  577            "ld %r0, (8*40)(%r1)\n" 
  579            "ld  %r0, (8*41)(%r1)\n" 
  581            "addi %r1, %r1, (8*42)\n" 
  585#error "Unsupported architecture." 
  589    inline bool fiber_swapcontext(fiber_context* out_ctx, fiber_context* in_ctx) {
 
  590        fiber_swap_stack(&out_ctx->current_sp, in_ctx->current_sp);
 
  594    inline bool fiber_destroy_context(fiber_context* ctx) {
 
  595        memset(ctx, 0, 
sizeof(fiber_context));
 
  604namespace asyncpp::detail {
 
  605    struct stack_context {
 
  610    inline bool fiber_allocate_stack(stack_context& ctx, 
size_t size) 
noexcept {
 
  611        static size_t pagesize = []() {
 
  613            ::GetSystemInfo(&si);
 
  614            return static_cast<size_t>(si.dwPageSize);
 
  618        const auto page_count = (size + pagesize - 1) / pagesize;
 
  619        size = page_count * pagesize;
 
  620        ctx.stack_size = size;
 
  624    inline bool fiber_deallocate_stack(stack_context& ctx) 
noexcept { 
return true; }
 
  626    struct fiber_context {
 
  628        void (*start_fn)(
void* arg);
 
  632    inline bool fiber_makecontext(fiber_context* ctx, 
const stack_context& stack, 
void (*entry_fn)(
void* arg),
 
  634        static void (*wrapper)(LPVOID) = [](LPVOID param) {
 
  635            auto ctx = 
static_cast<fiber_context*
>(param);
 
  636            ctx->start_fn(ctx->start_arg);
 
  638        ctx->fiber_handle = CreateFiber(stack.stack_size, wrapper, ctx);
 
  639        if (ctx->fiber_handle == NULL) 
return false;
 
  640        ctx->start_fn = entry_fn;
 
  641        ctx->start_arg = arg;
 
  645    inline bool fiber_swapcontext(fiber_context* out, fiber_context* in) {
 
  646#if (_WIN32_WINNT > 0x0600) 
  647        if (::IsThreadAFiber() == FALSE) {
 
  648            out->fiber_handle = ::ConvertThreadToFiber(
nullptr);
 
  650            out->fiber_handle = ::GetCurrentFiber();
 
  653        out->fiber_handle = ::ConvertThreadToFiber(
nullptr);
 
  654        if (out->fiber_handle == NULL) {
 
  655            if (::GetLastError() != ERROR_ALREADY_FIBER) 
return false;
 
  656            out->fiber_handle = ::GetCurrentFiber();
 
  659        if (out->fiber_handle == NULL) 
return false;
 
  660        SwitchToFiber(in->fiber_handle);
 
  664    inline bool fiber_destroy_context(fiber_context* ctx) {
 
  665        DeleteFiber(ctx->fiber_handle);
 
  666        ctx->fiber_handle = NULL;
 
  673    template<
typename TReturn>
 
  676namespace asyncpp::detail {
 
  677    struct fiber_handle_base {
 
  679        void (*resume_cb)(fiber_handle_base*) = 
nullptr;
 
  680        void (*destroy_cb)(fiber_handle_base*) = 
nullptr;
 
  682        detail::fiber_context main_context{};
 
  683        detail::fiber_context fiber_context{};
 
  684        detail::stack_context fiber_stack{};
 
  686        bool (*suspend_handler)(
void* ptr, coroutine_handle<> hndl) = 
nullptr;
 
  687        void* suspend_handler_ptr = 
nullptr;
 
  688        std::exception_ptr suspend_exception = 
nullptr;
 
  690        coroutine_handle<> continuation{};
 
  692        bool want_destroy = 
false;
 
  693        bool was_started = 
false;
 
  695        void* asan_handle = 
nullptr;
 
  696        const void* asan_parent_stack = 
nullptr;
 
  697        size_t asan_parent_stack_size{};
 
  700        void* tsan_parent = 
nullptr;
 
  701        void* tsan_fiber = 
nullptr;
 
  703#if ASYNCPP_HAS_VALGRIND 
  704        unsigned valgrind_id = 0;
 
  708#if defined(ASYNCPP_SO_COMPAT) 
  709    extern thread_local fiber_handle_base* g_current_fiber;
 
  711    inline static thread_local fiber_handle_base* g_current_fiber = 
nullptr;
 
  714#if defined(ASYNCPP_SO_COMPAT_IMPL) 
  715    thread_local fiber_handle_base* g_current_fiber = 
nullptr;
 
  718    struct fiber_destroy_requested_exception {};
 
  720    template<
typename FN>
 
  721    static coroutine_handle<> make_fiber_handle(
size_t stack_size, FN&& cbfn) {
 
  722        struct handle : fiber_handle_base {
 
  724            explicit handle(FN&& cbfn) : function(std::forward<FN>(cbfn)) {}
 
  726        static_assert(offsetof(handle, resume_cb) == 0);
 
  728        auto hndl = 
new handle(std::forward<FN>(cbfn));
 
  729        hndl->resume_cb = [](fiber_handle_base* hndl) {
 
  730            auto old = std::exchange(g_current_fiber, hndl);
 
  731            while (hndl->resume_cb != 
nullptr) {
 
  734                __sanitizer_start_switch_fiber(&asan_handle, hndl->fiber_stack.mmap_base, hndl->fiber_stack.mmap_size);
 
  737                hndl->tsan_parent = __tsan_get_current_fiber();
 
  738                __tsan_switch_to_fiber(hndl->tsan_fiber, 0);
 
  740                detail::fiber_swapcontext(&hndl->main_context, &hndl->fiber_context);
 
  742                const void* fiber_stack;
 
  743                size_t fiber_stack_size;
 
  744                __sanitizer_finish_switch_fiber(asan_handle, &fiber_stack, &fiber_stack_size);
 
  745                assert(fiber_stack == hndl->fiber_stack.mmap_base);
 
  746                assert(fiber_stack_size == hndl->fiber_stack.mmap_size);
 
  748                if (hndl->suspend_handler) {
 
  749                    auto handler = std::exchange(hndl->suspend_handler, 
nullptr);
 
  750                    auto ptr = std::exchange(hndl->suspend_handler_ptr, 
nullptr);
 
  752                        if (handler(ptr, coroutine_handle<>::from_address(
static_cast<void*
>(hndl)))) 
break;
 
  753                    } 
catch (...) { hndl->suspend_exception = std::current_exception(); }
 
  756            g_current_fiber = old;
 
  757            if (hndl->resume_cb == 
nullptr && hndl->continuation != 
nullptr) { hndl->continuation.resume(); }
 
  759        hndl->destroy_cb = [](fiber_handle_base* hndl) {
 
  761            if (hndl->resume_cb != 
nullptr && hndl->was_started) {
 
  762                hndl->want_destroy = 
true;
 
  763                hndl->resume_cb(hndl);
 
  764                assert(hndl->resume_cb == 
nullptr);
 
  767            __tsan_destroy_fiber(hndl->tsan_fiber);
 
  769#if ASYNCPP_HAS_VALGRIND 
  770            VALGRIND_STACK_DEREGISTER(hndl->valgrind_id);
 
  772            detail::fiber_destroy_context(&hndl->fiber_context);
 
  773            detail::fiber_deallocate_stack(hndl->fiber_stack);
 
  774            delete static_cast<handle*
>(hndl);
 
  777        hndl->tsan_fiber = __tsan_create_fiber(0);
 
  779        if (!detail::fiber_allocate_stack(hndl->fiber_stack, stack_size)) {
 
  781            __tsan_destroy_fiber(hndl->tsan_fiber);
 
  784            throw std::bad_alloc();
 
  786        if (!detail::fiber_makecontext(
 
  787                &hndl->fiber_context, hndl->fiber_stack,
 
  789                    auto hndl = static_cast<handle*>(ptr);
 
  791                    __sanitizer_finish_switch_fiber(hndl->asan_handle, &hndl->asan_parent_stack,
 
  792                                                    &hndl->asan_parent_stack_size);
 
  794                    hndl->was_started = true;
 
  797                    } catch (
const fiber_destroy_requested_exception&) {} 
 
  798                    hndl->resume_cb = 
nullptr;
 
  800                    __sanitizer_start_switch_fiber(
nullptr, hndl->asan_parent_stack, hndl->asan_parent_stack_size);
 
  803                    assert(hndl->tsan_fiber == __tsan_get_current_fiber());
 
  804                    __tsan_switch_to_fiber(hndl->tsan_parent, 0);
 
  806                    detail::fiber_swapcontext(&hndl->fiber_context, &hndl->main_context);
 
  811            __tsan_destroy_fiber(hndl->tsan_fiber);
 
  813            fiber_deallocate_stack(hndl->fiber_stack);
 
  815            throw std::bad_alloc();
 
  817#if ASYNCPP_HAS_VALGRIND 
  819            VALGRIND_STACK_REGISTER(hndl->fiber_stack.mmap_base,
 
  820                                    static_cast<uint8_t*
>(hndl->fiber_stack.mmap_base) + hndl->fiber_stack.mmap_size);
 
  822        return coroutine_handle<>::from_address(
static_cast<void*
>(hndl));
 
  826    static auto fiber_await(T&& awaiter) {
 
  829        if (std::uncaught_exceptions() != 0) std::terminate();
 
  830        if (!
static_cast<bool>(awaiter.await_ready())) {
 
  840            auto hndl = detail::g_current_fiber;
 
  841            assert(hndl != 
nullptr);
 
  843            assert(__builtin_frame_address(0) > hndl->fiber_stack.mmap_base);
 
  844            assert(__builtin_frame_address(0) <
 
  845                   (
static_cast<uint8_t*
>(hndl->fiber_stack.mmap_base) + hndl->fiber_stack.mmap_size));
 
  847            using AwaitResult = 
decltype(awaiter.await_suspend(std::declval<coroutine_handle<>>()));
 
  848            hndl->suspend_handler = [](
void* ptr, coroutine_handle<> hndl) {
 
  849                if constexpr (std::is_same_v<AwaitResult, void>) {
 
  850                    static_cast<T*
>(ptr)->await_suspend(hndl);
 
  852                } 
else if constexpr (std::is_same_v<AwaitResult, bool>) {
 
  853                    return static_cast<T*
>(ptr)->await_suspend(hndl);
 
  855                    static_cast<T*
>(ptr)->await_suspend(hndl).resume();
 
  859            hndl->suspend_handler_ptr = &awaiter;
 
  862            __sanitizer_start_switch_fiber(&asan_handle, hndl->asan_parent_stack, hndl->asan_parent_stack_size);
 
  865            assert(hndl->tsan_fiber == __tsan_get_current_fiber());
 
  866            __tsan_switch_to_fiber(hndl->tsan_parent, 0);
 
  868            detail::fiber_swapcontext(&hndl->fiber_context, &hndl->main_context);
 
  870            __sanitizer_finish_switch_fiber(asan_handle, &hndl->asan_parent_stack, &hndl->asan_parent_stack_size);
 
  872            if (hndl->suspend_exception != 
nullptr)
 
  873                std::rethrow_exception(std::exchange(hndl->suspend_exception, 
nullptr));
 
  874            if (hndl->want_destroy) {
 
  876                throw fiber_destroy_requested_exception{};
 
  879        return awaiter.await_resume();
 
  882    struct fib_await_helper {
 
  885        auto operator=(T&& awaiter) {
 
  886            return fiber_await(std::forward<T>(awaiter));
 
  898        coroutine_handle<> m_handle;
 
  913        template<
typename FN>
 
  914        explicit fiber(FN&& function, 
size_t stack_size = 262144)
 
  915            requires(!std::is_same_v<FN, fiber>)
 
  916            : m_handle(detail::make_fiber_handle(stack_size, std::forward<FN>(function))) {}
 
 
  918        constexpr fiber() noexcept : m_handle(
nullptr) {}
 
  921            if (m_handle) m_handle.destroy();
 
 
  924        fiber(
fiber&& other) noexcept : m_handle(std::exchange(other.m_handle, 
nullptr)) {}
 
  927            if (&other != 
this) {
 
  928                if (m_handle) m_handle.destroy();
 
  929                m_handle = std::exchange(other.m_handle, 
nullptr);
 
 
  945            return detail::fiber_await(std::forward<
decltype(awaiter)>(awaiter));
 
 
  953            if (!m_handle) 
throw std::logic_error(
"empty fiber");
 
  955                coroutine_handle<> m_handle;
 
  956                [[nodiscard]] 
bool await_ready() 
const noexcept { 
return m_handle.done(); }
 
  957                [[nodiscard]] coroutine_handle<> await_suspend(coroutine_handle<> hdl)
 const {
 
  958                    auto ctx = 
static_cast<detail::fiber_handle_base*
>(m_handle.address());
 
  959                    if (ctx->continuation != 
nullptr) 
throw std::logic_error(
"already awaited");
 
  960                    ctx->continuation = hdl;
 
  963                constexpr void await_resume() 
const noexcept {}
 
  965            return awaiter{m_handle};
 
 
  972        auto operator co_await() { 
return await(); }
 
 
  978    template<
typename TReturn>
 
  980        std::unique_ptr<std::optional<TReturn>> m_result{};
 
  996        template<
typename FN>
 
  997        explicit fiber(FN&& function, 
size_t stack_size = 262144)
 
  998            requires(!std::is_same_v<FN, fiber>)
 
  999            : m_result(std::make_unique<std::optional<TReturn>>()),
 
 1000              m_base([function = std::forward<FN>(function), res = m_result.get()]() { res->emplace(function()); },
 
 
 1005        fiber(
fiber&& other) noexcept : m_result(std::move(other.m_result)), m_base(std::move(other.m_base)) {}
 
 1008            if (&other != 
this) {
 
 1009                m_base = std::move(other.m_base);
 
 1010                m_result = std::move(other.m_result);
 
 
 1024        template<
typename T>
 
 1026            return detail::fiber_await(std::forward<T>(awaiter));
 
 
 1034            if (!m_result) 
throw std::logic_error(
"empty fiber");
 
 1036                decltype(m_base.operator 
co_await()) m_awaiter;
 
 1037                std::optional<TReturn>* m_result;
 
 1038                [[nodiscard]] 
bool await_ready() 
const noexcept { 
return m_awaiter.await_ready(); }
 
 1039                [[nodiscard]] coroutine_handle<> await_suspend(coroutine_handle<> hdl)
 const {
 
 1040                    return m_awaiter.await_suspend(hdl);
 
 1042                auto await_resume() 
const noexcept {
 
 1043                    assert(m_result->has_value());
 
 1044                    return m_result->value();
 
 1047            return awaiter{m_base.
await(), m_result.get()};
 
 
 1055            if (!m_result) 
throw std::logic_error(
"empty fiber");
 
 1057                decltype(m_base.operator 
co_await()) m_awaiter;
 
 1058                std::optional<TReturn>* m_result;
 
 1059                [[nodiscard]] 
bool await_ready() 
const noexcept { 
return m_awaiter.await_ready(); }
 
 1060                [[nodiscard]] coroutine_handle<> await_suspend(coroutine_handle<> hdl)
 const {
 
 1061                    return m_awaiter.await_suspend(hdl);
 
 1063                auto await_resume() 
const noexcept {
 
 1064                    assert(m_result->has_value());
 
 1065                    return std::move(m_result->value());
 
 1068            return awaiter{m_base.
await(), m_result.get()};
 
 
 1075        auto operator co_await() & { 
return await(); }
 
 1080        auto operator co_await() && { 
return await(); }
 
 
 1083    template<
typename FN>
 
 1084    fiber(FN&&) -> fiber<std::invoke_result_t<FN>>;
 
 1087#if ASYNCPP_FIBER_KEYWORDS 
 1088#define fib_await (asyncpp::detail::fib_await_helper{}) = 
~fiber()
Destructor.
Definition fiber.h:920
 
auto await()
Get an awaitable for this fiber.
Definition fiber.h:952
 
constexpr fiber() noexcept
Construct an empty fiber handle.
Definition fiber.h:918
 
fiber & operator=(fiber &&other) noexcept
Move constructor. The moved from handle will be empty.
Definition fiber.h:926
 
fiber(FN &&function, size_t stack_size=262144)
Construct a new fiber for the specified entry function.
Definition fiber.h:914
 
static auto fiber_await(T &&awaiter)
Await a standard C++20 coroutine awaitable.
Definition fiber.h:944
 
fiber(fiber &&other) noexcept
Move constructor. The moved from handle will be empty.
Definition fiber.h:924
 
Fiber class providing a stackfull coroutine.
Definition fiber.h:979
 
static auto fiber_await(T &&awaiter)
Await a standard C++20 coroutine awaitable.
Definition fiber.h:1025
 
constexpr fiber() noexcept=default
Construct an empty fiber handle.
 
auto await() &&
Get an awaitable for this fiber.
Definition fiber.h:1054
 
fiber & operator=(fiber &&other) noexcept
Move constructor. The moved from handle will be empty.
Definition fiber.h:1007
 
auto await() &
Get an awaitable for this fiber.
Definition fiber.h:1033
 
fiber(FN &&function, size_t stack_size=262144)
Construct a new fiber for the specified entry function.
Definition fiber.h:997
 
Provides a consistent import interface for coroutine, experimental/coroutine or a best effort fallbac...