On Mon, Sep 19, 2016 at 11:21 AM, Michael Steinberg <michsteinb@gmail.com> wrote:
Hello,

is there some way to temporarily run a function on the main stack? I played around a bit, but failed ultimately since the first stub function to be called is getting a "null" context which I assume to be only a valid "return-context".

We're facing a problem where a dialog run modally inside a context runs webkit, which triggers garbage collection, which fails miserably since it assumes we're on the "native" stack. If it were possible to run something "on-top" of the main stack, this could maybe be circumvented.

Thank you,
Michael

_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

I have a similar problem I solved by providing a mechanism for storing the "root" context. Storing this is a bit tricky, since the context you're jumping to is responsible for performing your action (assuming you're using Context v2). My own fiber implementation provides the ability to jump to yield, wait and jump to root. Hopefully this is helpful for you.

struct destination_action
{
    enum class goal { root, ready, wait };

    goal  request;
    void* addr = nullptr;
};

using context = boost::context::execution_context<destination_action>;

All context jumps go through a simple helper method (functions leading into this are simply creating a destination_action instance with what the caller wants to do).

void service::jump_to(context cxt, destination_action request) noexcept
{
    std::tie(cxt, request) = cxt(request);
    save_caller(std::move(cxt), request);
}


The save_caller function is pretty simple. You probably only care about when request is goal::root, but I'll drop the whole thing for completeness.

void service::save_caller(context&& cxt, destination_action request) noexcept
{
    // The stack terminated, so don't bother saving it.
    if (!cxt)
        return;


    switch (request.request)
    {
    case destination_action::goal::ready:
        _scheduler.ready(std::move(cxt));
        break;
    case destination_action::goal::wait:
        _scheduler.wait(request.addr, std::move(cxt));
        break;
    case destination_action::goal::root:
        ASSERT(!_root_context) << "Already have a root runner";
        _root_context = std::move(cxt);
        break;

    default:
        ASSERT(false) << "Corruption? " << request.request;
    }
}


Ultimately, I provide a run function which is meant to be called by the root context.

void service::run()
{
    if (_in_run)
        throw invalid_state("This service is already running.");

    _in_run = true;
    SCOPE_EXIT { _in_run = false; };

    while (_running)
    {
        if (auto next = pop_next_routine())

        {
            destination_action action;
            action.request = destination_action::goal::root;

            jump_to(std::move(next), action);
        }
        else
        {
            // No routine to run...must be a root request
            auto fn = _root_requests.pop();
            std::move(fn)();
        }
    }
}

Hope this helps!

--
Travis Göckel