Boost logo

Boost :

Subject: Re: [boost] [context review]
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2011-03-25 09:01:05


On Fri, Mar 25, 2011 at 12:29 PM, Artyom <artyomtnk_at_[hidden]> wrote:
>>
>> The first issue  is that the destructor of the context class will (at
>> least by default)  happily destroy the stack. This unfortunately will
>> leak any resource owned by  any object on the stack; This is not unlike
>> destroying an allocator before  having destroyed all allocated object.
>>
>
> I want to add a small point.
>
> When I reviewed Boost.Context I had thought at the begging
> about it but then I realized that it is very problematic requirement.
>
> The only portable way to abort stack unwinding is to throw
> an exception and catch it at top level.
>
>     context_1.jump_to(context_2);
>        // throws something like fiber interrupted.
>        // if stack is destroyed.
>
> Actually it is quite problematic, for example what if
> there is a code that does
>
>  try {
>     ...
>     context_1.jump_to(context_2);
>     ...
>  }
>  catch(...) {
>     // Ignore all errors
>  }
>
> The stack would not be unwinded and the destructor of the
> stack would be stuck in execution of current destroyed thread.
>

There are two solutions:

a) require that that the unwind exception not be swallowed. It can
either be made unswallowable by having a trowing destructor (IIRC this
is how GCC implements the unwinding exception) or simply mark the
context as being in the unwinding and assert at next jump_to from that
context.

b) do not unwind in the destructor but assert that the stack is
unwound. A separate terminate() function can be used to unwind the
stack. This function would restore the context, try to unwind it and
return to the terminator context if the stack is unwound safely. When
control reaches back to the terminator context, directly or
indirectly, if the stack has not been unwound an exception is thrown
from terminate().

I opted for option a on my coroutine implementation, but now I think
it is too harsh and I favor option b better. Option b is similar to
std::thread which requires a joinable thread to be joined before
calling the destructor.

-- 
gpd

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk