structured exceptions for UNIXs -- the hard way

On UNIXs one does not get around signals. They are used for everything. E.g. using memory mapped io is impossible without dealing with signals. E.g. somebody may edit the file which is mapped into your process thereby truncating it and invalidating some part of the memory. Or one may be writing into a sparse file via memory mapped io and the result of "out of disk space" is also a signal. Then there are such sick solutions as setjmp()/longjmp(). Could they be packed into some class to enable some kind of structured exceptions on UNIXs? #include <setjmp.h> #include <vector> static std::vector<jmp_buf> s_sStack; static void signalHandler(void) { if (s_sStack.size()) { jmp_buf s = s_sStack.back(); s_sStack.pop_back(); longjmp(s); } } struct CSetLongJmp { CSetLongJmp(void) { s_sStack.push_back(jmp_buf()); if (setjmp(s_sStack.back())) throw "something"; } ~CSetLongJmp(void) { s_sStack.pop_back(); } }; This class would need to be part of anything which needs to be protected against signals: std::string s; CSetLongJmp s1; useString(s); Peter Foelsche

AMDG On 09/20/2011 02:04 PM, Peter Foelsche wrote:
static std::vector<jmp_buf> s_sStack;
static void signalHandler(void) { if (s_sStack.size()) { jmp_buf s = s_sStack.back(); s_sStack.pop_back(); longjmp(s); } }
I didn't think longjmp was async signal safe. In Christ, Steven Watanabe

"Steven Watanabe" <watanabesj@gmail.com> wrote in message news:4E7906C4.9050601@providere-consulting.com...
I didn't think longjmp was async signal safe.
from what I've read it is only not safe to be callled from a nested signal handler -- means a signal handler called from another signalhandler.

AMDG On 09/21/2011 07:14 AM, Peter Foelsche wrote:
"Steven Watanabe" <watanabesj@gmail.com> wrote in message news:4E7906C4.9050601@providere-consulting.com...
I didn't think longjmp was async signal safe.
from what I've read it is only not safe to be callled from a nested signal handler -- means a signal handler called from another signalhandler.
But, std::vector<jmp_buf> is not volatile sig_atomic_t, so the value of s_sStack is unspecified inside the signal handler according to 1.9 p9. In Christ, Steven Watanabe

"Steven Watanabe" <watanabesj@gmail.com> wrote in message news:4E79F4AF.8040906@providere-consulting.com...
But, std::vector<jmp_buf> is not volatile sig_atomic_t, so the value of s_sStack is unspecified inside the signal handler according to 1.9 p9.
ok -- would plain C work? volatile jmp_buf s_sStack[1024]; volatile std::size_t s_iStackPos; or even: volatile jmp_buf *s_pStack; volatile std::size_t s_iStackPos; But -- can one longjmp into a function (the constructor) which has already been left? I think such things should be left up to the developers of the compiler! I hope the guys at G++ are listening... Maybe one day they get the idea, that not every idea from microsoft is so bad.

Peter Foelsche wrote: [...]
I hope the guys at G++ are listening... Maybe one day they get the idea, that not every idea from microsoft is so bad.
IIRC GCC/G++ already implements two-phase EH (that's what SEH basically is in essence) according to http://sourcery.mentor.com/public/cxx-abi/abi-eh.html which states "A two-phase exception-handling model is not strictly necessary to implement C++ language semantics, but it does provide some benefits. For example, the first phase allows an exception-handling mechanism to dismiss an exception before stack unwinding begins, which allows resumptive exception handling (correcting the exceptional condition and resuming execution at the point where it was raised). While C++ does not support resumptive exception handling, other languages do, and the two-phase model allows C++ to coexist with those languages on the stack. " regards, alexander.

On Wed, Sep 21, 2011 at 3:55 PM, Peter Foelsche <foelsche@sbcglobal.net> wrote:
I think such things should be left up to the developers of the compiler! I hope the guys at G++ are listening...
FWIW, with a recent GCC on Linux you can throw exceptions from signal handlers and they will be correctly handled (this is required to support Java and I think Ada as well). You need to compile with -fnon-call-exceptions or -fasynchronous-exceptions. These have been available for quite a while but were very buggy in C and C++ until recently.
Maybe one day they get the idea, that not every idea from microsoft is so bad.
Async exceptions do have their use; the problem is code must be carefully designed to deal with async exceptions so you do not want these to be enabled by default. Also they have non-trivial costs (async unwind tables can be very large). -- gpd

"Giovanni Piero Deretta" <gpderetta@gmail.com> wrote in message news:CAL52AavW0uSnwGf_O9HFSviATUiV=rt0TMjEbysm5Z7d6J4jCw@mail.gmail.com...
FWIW, with a recent GCC on Linux you can throw exceptions from signal handlers and they will be correctly handled (this is required to support Java and I think Ada as well). You need to compile with -fnon-call-exceptions or -fasynchronous-exceptions. These have been available for quite a while but were very buggy in C and C++ until recently.
Thanks! This is exactly what is needed! I'm curious that I hear about it only now. I'll try this tomorrow. What man g++ says about this option is pretty terse. The Intel compiler at least said, that it allows throwing exceptions from signal handler for SIGSEGV or SIGFPE. Peter

Le 20.09.2011 22:04, Peter Foelsche a écrit :
Then there are such sick solutions as setjmp()/longjmp(). Could they be packed into some class to enable some kind of structured exceptions on UNIXs?
The setcontext ( http://en.wikipedia.org/wiki/Setcontext ) functions are more flexible and POSIX.

Peter Foelsche wrote:
On UNIXs one does not get around signals. They are used for everything. E.g. using memory mapped io is impossible without dealing with signals. E.g. somebody may edit the file which is mapped into your process thereby truncating it and invalidating some part of the memory. Or one may be writing into a sparse file via memory mapped io and the result of "out of disk space" is also a signal.
Then there are such sick solutions as setjmp()/longjmp(). Could they be packed into some class to enable some kind of structured exceptions on UNIXs?
#include <setjmp.h> #include <vector>
static std::vector<jmp_buf> s_sStack;
static void signalHandler(void) { if (s_sStack.size()) { jmp_buf s = s_sStack.back(); s_sStack.pop_back(); longjmp(s); } }
struct CSetLongJmp { CSetLongJmp(void) { s_sStack.push_back(jmp_buf()); if (setjmp(s_sStack.back())) throw "something"; } ~CSetLongJmp(void) { s_sStack.pop_back(); } };
There are a few problems with that, including longjmp() and std::vector not being signal-safe according to the standards. I think that in practice you can probably get away with using them in most cases though. Then there is this: { CSetLongJmp a; NonTrivialType t; do_something_that_signals(); } Is t's dtor called? Finally, you have the problem that the stack frame in which setjmp() is called is already out of scope by the time that you try to longjmp() to it. You can only do this by putting the actual setjmp() call inline. Macros can help with this sort of thing. Regards, Phil.

Is there any reason this should be considered on-topic for the Boost list? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Peter Foelsche <foelsche <at> sbcglobal.net> writes:
On UNIXs one does not get around signals. They are used for everything. E.g. using memory mapped io is impossible without dealing with signals. E.g. somebody may edit the file which is mapped into your process thereby truncating it and invalidating some part of the memory. Or one may be writing into a sparse file via memory mapped io and the result of "out of disk space" is also a signal.
Then there are such sick solutions as setjmp()/longjmp(). Could they be packed into some class to enable some kind of structured exceptions on UNIXs?
boost::execution_monitor deals with these issues. From what I understood this is exactly what you want. Gennadiy
participants (9)
-
Alexander Terekhov
-
Dave Abrahams
-
Gennadiy Rozental
-
Giovanni Piero Deretta
-
Mathias Gaunard
-
Peter Foelsche
-
Phil Endecott
-
remi.chateauneu@gmx.de
-
Steven Watanabe