c++boehm-gcboost-contextboost-coroutine

How to use Boost.Coroutine with Boehm GC?


Boost.Coroutine allocates its own call stacks. Does Boehm GC consider pointers on these stacks as roots, and if not how can I make it do that? After a context switch to a coroutine, Boehm terminates the program.


Solution

  • Currently boost doesn't provide a way to hook into segmented stack allocations, so here's a solution for fixed size stacks.

    #include <gc/gc.h>
    #include <gc/gc_cpp.h>
    #include <boost/coroutine2/coroutine.hpp>
    #include <boost/coroutine2/protected_fixedsize_stack.hpp>
    #include <boost/context/stack_context.hpp>
    
    class BoehmGCStackAllocator {
        boost::coroutines2::protected_fixedsize_stack stack;
    
        // This is specific to boost::coroutines2::protected_fixedsize_stack.
        // The stack protection page is included in sctx.size, so we have to
        // subtract one page size from the stack size.
        std::size_t pfss_usable_stack_size(boost::context::stack_context &sctx) {
          return sctx.size - boost::context::stack_traits::page_size();
        }
    
      public:
        boost::context::stack_context allocate() {
            auto sctx = stack.allocate();
    
            // Despite what the boost docs warn, the only *implemented* stack direction
            // is "down". This is why we subtract the stack size.
            GC_add_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
            return sctx;
        }
    
        void deallocate(boost::context::stack_context sctx) {
            GC_remove_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
            stack.deallocate(sctx);
        }
    
    };
    

    You then provide it when creating the coroutine.

    auto coro = boost::coroutines2::coroutine<std::string>::pull_type(BoehmGCStackAllocator{}, [&](coro_t::push_type & yield) {
       // ...
    }