[comp.unix.questions] question about signal

mar@hpclmar.HP.COM (Michelle Ruscetta) (09/25/87)

 Question about signal():

  Should the return from a signal handling routine specified by a call
  to signal() go to the instruction which caused the signal, or to the 
  instruction immediately following that which caused the signal?

  For example: 

  void (*p_my_handler)();

  main()
  {  
     extern void my_handler();
     int y = 0;
     int x = 3;
     p_my_handler = my_handler:
     signal(SIGFPE, p_my_handler);    
     x = x/y; 			      /* should my_handler return to here? */
     printf("return from signal\n");  /* or should my_handler return to here? */
  }

  void my_handler() 
  {
     signal(SIGFPE, SIG_IGN);
     /* do something useful */
     signal(SIGFPE, p_my_handler); 
  }


 ---------------------------

  I have run this example on two different machines, with different results; 
  (both were running implementations of System V) one returned to the statement 
  following that which cause the signal (the printf), and the other returned 
  to the instruction which caused the signal -- hence throwing the program 
  into an infinite loop continuously executing x/y and catching the floating 
  point exception.

  I know it is not very good practice to return from signal-handlers
  but this question came up in a discussion and I would be interested to
  hear opinions as to which is the 'correct' way for signal to handle this.

gwyn@brl-smoke.UUCP (09/28/87)

In article <720001@hpclmar.HP.COM> mar@hpclmar.HP.COM (Michelle Ruscetta) writes:
>  Should the return from a signal handling routine specified by a call
>  to signal() go to the instruction which caused the signal, or to the 
>  instruction immediately following that which caused the signal?

If it's an asynchronous trap, it should complete the interrupted
instruction sequence.  If it's a synchronous trap (e.g. SIGFPE),
there is no "right" answer.  Presumably the synchronous exception
occurred because some machine operation had invalid operands;
unless you can be sure that the signal handler has fixed the
operands (which is almost never the case, due to code optimization
etc.), retrying the faulting instruction would just cause another
trap.

Portable, robust programs should not just return from a SIGFPE
handler.

matt@oddjob.UUCP (10/01/87)

Michelle Ruscetta writes:
) 
)  Question about signal():
) 
)   Should the return from a signal handling routine specified by a call
)   to signal() go to the instruction which caused the signal, or to the 
)   instruction immediately following that which caused the signal?
) 
)   For example:    ...
)
)   I have run this example on two different machines, with different results; 
)   [one resumed at the instruction after the FPE], and the other returned 
)   to the instruction which caused the signal

Was the second machine a VAX-11/750?  If I remember rightly, 750's
have a microcode bug in the treatment of floating point exceptions
which causes exactly the behavior you say.
________________________________________________________
Matt	     University		matt@oddjob.uchicago.edu
Crawford     of Chicago     {astrovax,ihnp4}!oddjob!matt

rneitzel@udenva.UUCP (RICHARD NEITZEL ) (10/01/87)

In article <720001@hpclmar.HP.COM> mar@hpclmar.HP.COM (Michelle Ruscetta) writes:
>
> Question about signal():
>
>  Should the return from a signal handling routine specified by a call
>  to signal() go to the instruction which caused the signal, or to the 
>  instruction immediately following that which caused the signal?
>
>  For example: 
>
>  void (*p_my_handler)();
>
>  main()
>  {  
>     extern void my_handler();
>     int y = 0;
>     int x = 3;
>     p_my_handler = my_handler:
>     signal(SIGFPE, p_my_handler);    
>     x = x/y; 			      /* should my_handler return to here? */
>     printf("return from signal\n");  /* or should my_handler return to here? */
>  }

In my opinion this depends partially on the way in which you look at the
problem. Returning to the line that caused the signal
might well trigger the signal again, putting the program into an infinite loop.
After all, the chances of your signal handling routine knowing EXACTLY what to
do are slim. 

There is however the problem that a C line does not map to a single
machine instruction. For example, suppose that the line above where changed to:
	x = x/y + (x - y);
Now, do you want the entire line to complete, even if the division triggers a 
signal? More then likely, yes you do.

The answer probably is that there need to be two classes of signals (whether
in fact or in conception), synchronous and asynchronous. The first should be 
used for events that are of a fixed nature, such as floating point exceptions.
The latter are for events that are unpredictable. Further, synchronous 
signals should be limited to events from which you do not normally exspect to
return, while the other case is for events that do not require that the normal
program flow be terminated. 

It is my opinion that the best solution would be to have these two types of
signals, but barring that I would prefer that all signals behave in an 
asynchronous nature, leaving it to the user to use those signals that are
inappropriate in a strictly synchronous manner.

'I'd gladly pay you Tuesday for a hamburger today'

			Richard Neitzel

mar@hpclmar.UUCP (10/02/87)

/ hpclmar:comp.unix.questions / matt@oddjob.UChicago.EDU (I am not a Grook) /  3:43 pm  Sep 30, 1987 /

> Was the second machine a VAX-11/750?  If I remember rightly, 750's
> have a microcode bug in the treatment of floating point exceptions
> which causes exactly the behavior you say.
> ________________________________________________________
> Matt	     University		matt@oddjob.uchicago.edu
> Crawford     of Chicago     {astrovax,ihnp4}!oddjob!matt

 No, one machine was a 68020-based architecture (the hp9000s320)
 and the other was the HPPA (risc) architecture (hp9000s840).

 The s320 began execution after the line which caused the floating-point
 trap. The s840 begins execution at the instruction which caused the
 floating-point trap (causing the given program goes into an infinite loop).

john@frog.UUCP (John Woods, Software) (10/06/87)

In article <4248@udenva.UUCP>, rneitzel@udenva.UUCP (RICHARD NEITZEL ) writes:
> In article <720001@hpclmar.HP.COM> mar@hpclmar.HP.COM (Michelle Ruscetta) writes:
> > Question about signal():
> >  Should the return from a signal handling routine specified by a call
> >  to signal() go to the instruction which caused the signal, or to the 
> >  instruction immediately following that which caused the signal?
> >  void (*p_my_handler)();
> >  main()
> >  {  
> >     extern void my_handler();
> >     int y = 0;
> >     int x = 3;
> >     p_my_handler = my_handler:
> >     signal(SIGFPE, p_my_handler);    
> >     x = x/y;		      /* should my_handler return to here? */
> >     printf("return from signal\n");  /* or to here? */
> >  }
> 
I would argue that the signal should return to the instruction causing the
problem, if it returns at all.  Presumably, your handler will either fix
up the problem to allow the instruction to complete correctly (e.g., it
would determine that one of the arguments is 0.0, print a message, stuff a
1.0 into the register or temporary, and return), it would bypass the
effects of the instruction and advance the program counter that will be
returned to (e.g., it prints a message, stores an IEEE infinity into the
result of the instruction (register, memory location, whatever), bumps the
PC, and returns), or it prints out an error message, maybe a stack backtrace,
and craps out again with a core dump.

Note that two of these aren't portable things.  Furthermore, they may become
impossible in processors with separate, asynchronous, floating point units
(e.g. the venerable PDP-11), or with lots of internal pipelining:  how does
one "properly" re-do

	divf	fr0,fr1
	inc	r0
	addf	fr1,fr2

if the divf gets an exception AFTER the 'inc r0' has executed?

In short, it is probably easiest to offer to repair damage from an exception
if the exception handler is told which instruction faulted and is allowed
to return to it, but in the *general* case the only useful thing a signal
handler can do in this case is:

my_FPE_handler() {
	fprintf(stderr,"Ah, geez, a floating point exception happened!\n");
	abort();
}

--
John Woods, Charles River Data Systems, Framingham MA, (617) 626-1101
...!decvax!frog!john, ...!mit-eddie!jfw, jfw@eddie.mit.edu

"Cutting the space budget really restores my faith in humanity.  It
eliminates dreams, goals, and ideals and lets us get straight to the
business of hate, debauchery, and self-annihilation."
		-- Johnny Hart

gwyn@brl-smoke.ARPA (Doug Gwyn ) (10/08/87)

In article <1659@frog.UUCP> john@frog.UUCP (John Woods, Software) writes:
-...  Presumably, your handler will either fix
-up the problem to allow the instruction to complete correctly (e.g., it
-would determine that one of the arguments is 0.0, print a message, stuff a
-1.0 into the register or temporary, and return)...

It is not in general possible to "fix up the problem" with portable C code.

You shouldn't print messages from signal handlers; the associated library
routines are in general non-reentrant due to possibly incomplete manipulation
of internal data structures when interrupted.

-... but in the *general* case the only useful thing a signal
-handler can do in this case is:
-my_FPE_handler() {
-	fprintf(stderr,"Ah, geez, a floating point exception happened!\n");
-	abort();
-}

No, it is often the case that an error flag can be set and a longjmp()
performed to reenter the application's main control loop.