2

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.

2 Answers2

2

Presumably the code in Boost.Coroutine saves a pointer to the call stack it allocates, and stores it in one of the "usual" places to store pointers (e.g., some pointer variable).

If that is the case, then yes, the GC will "chase" the pointer from the variable in which it's stored to the call stack, and from there (recursively) through any pointers it contains.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Boehm crashes, saying it can't find the stack for the current thread. :( –  Oct 09 '15 at 19:55
1

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) {
   // ...
}
Robert Hensing
  • 6,708
  • 18
  • 23