octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: signal handling


From: John W. Eaton
Subject: Re: signal handling
Date: Thu, 14 Nov 2002 21:42:07 -0600

On 14-Nov-2002, Paul Kienzle <address@hidden> wrote:

| We can using sigaction, which allows you to mask signals while the handler
| is active.

OK.

| > The only place we would jump from would be the interrupt
| > handler, and I think that when it is executing, interrupts are
| > ignored.
| 
| I can't find anything definitive about that for signal().

Maybe I was imagining it.  In any case, it should not be too hard to
block them in the other signal handlers.

| > Hmm.  In any case, you're right that we should be using
| > sig{set,long}jmp instead, if they exist (and I would expect them to be
| > present on all modern systems).  I can make that change.

I've made changes for this, and I'm just about to check them in.

| > I also thought of another problem.  With my most recent changes, we
| > now only jump out of the signal handler when executing foreign code
| > (mostly Fortran) and that should be OK except when the foreign code
| > calls back to Octave.  For example, fsolve calls a user-defined
| > function written in C++ which then executes some interpreted Octave
| > code.  When that code is running, we should avoid jumping so that we
| > don't leak resources.  This means that the body of the user-supplied
| > function should be surrounded by a try-catch block and we should set
| > up to return from the signal handler instead of jumping, then throw
| > and exception, then jump from the try block back to the point where
| > the foreign code was intially called.
| 
| I played with this a long time ago, and I'm rusty on the details.  The
| foreign code has to be compiled with -fexceptions, but from the signal
| handler can't you simply throw an exception as usual?  I believe I was
| throwing the exception in the callback rather than the from the signal
| handler, but the idea is the same.

Does the foreign code have to be compiled with -fexceptions if we have
the following structure?

   fortran_code
     ...
     call user_defined_function_in_cxx
     ...
   end


   if (sigsegjmp (buf, 1))
     throw interrupt_exception ();
   else {
     interrupt_immediately++;  // i.e., jump from signal handler
     fortran_code ();
   }

   user_defined_function_in_cxx () {
     int save_interrupt_immediately = interrupt_immediately
     try
       {
         interrupt_immediately = 0;  // i.e., don't jump from SIGINT handler
         some_useful_calc ();
       }
     catch (interrupt_exception)
       {
         interrupt_immediately = save_interrupt_immediately;
         siglongjmp (back_to_location_of_call_to_fortran_code, 1);
       }
     interrupt_immediately = save_interrupt_immediately;
   }

This is what I was trying to describe in my previous message.  So we
just want to skip back over the fortran code because maybe it doesn't
give us a good way to say "bail out now!" from inside the user defined
function.

I've made some changes for this that I'm about to check in.  They
seemed to work fine on the example I tried -- sending SIGINT while the
lsode user function was executing ended up in the catch block and then
the jump back to the location of the sigsetjmp followed by an
exception to go back to the main loop was successful.

| If the foreign code has acquired resource they won't be released (C++
| doesn't know about them), but that is true even if you use siglongjmp
| as you are suggesting.

Right.  I'm just assuming that the foreign code doesn't acquire any
resources (true for the Fortran code that Octave uses, I think).

| The only way around it that I can see is if
| the foreign code can register and invoke unwind_protect code much like
| you are doing things now.

Would be possible, but maybe not always practical.

| Oh, but a lot of the code we are calling (e.g., atlas) may not have
| been compiled with -fexceptions, and that might mean we can't throw
| an exception from a signal invoked while that code is active.  We need
| to try this on various platforms.

OK.  Just to try to clarify, the exceptions are never thrown from the
signal handler.  The signal handler just sets a flag and returns.
Then we hit an OCTAVE_QUIT macro which throws the exception.  It's
caught before we get back to the fortran routine, then we jump over
that and back to C++, where we rethrow the exception.  These kinds of
blocks can be nested.

If we happen to catch SIGINT when the foreign code (fortran_code in
the above example) is executing, we will jump back to the location of
the previous sigsetjmp.  I think that's the best we can do unless we
want interrupts for long-running foreign code to be unresponsive
(and annoying).

I don't see anything in the g77 manual that says anything about
exceptions, and g77 -v doesn't show any options enabled for exception
handling.  My scheme above seemed to work OK (not that it will work on
all systems or with all compilers, of course).

jwe



reply via email to

[Prev in Thread] Current Thread [Next in Thread]