Boost logo

Boost Users :

Subject: Re: [Boost-users] boost::context "main" stack
From: Travis Gockel (travis_at_[hidden])
Date: 2016-09-19 14:05:40


On Mon, Sep 19, 2016 at 11:21 AM, Michael Steinberg <michsteinb_at_[hidden]>
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_at_[hidden]
> 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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net