
On Fri, Mar 25, 2011 at 12:29 PM, Artyom <artyomtnk@yahoo.com> 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