[comp.lang.c] Catching Signals in 'C'

ramsey@NCoast.ORG (Cedric Ramsey) (09/28/90)

Hello peoplekind. I have a question about the behavior of the
signal function. Firstly, I want to trap the control-c, break,
and other interrupt keys the user may use to stop a program.
I did this by ;

main()
{
  signal (SIGINT, (*handler1) ());
  signal (SIGQUIT, (*handler2) ());
  ... 
}


But, when I type a control-c the program handles the signal as
expected; however, when I type the control-c a second time the program 
doesn't catch it and simply exits. 

I don't know what went wrong. Does anybody outthere have any
thoughts or conjectures ? Any input is needed and desired.

Thanks,

Cedric A. Ramsey
Mail: ramsey@ncoast.ORG

pfalstad@bow.Princeton.EDU (Paul John Falstad) (09/28/90)

In article <1990Sep28.120043.17628@NCoast.ORG>, ramsey@NCoast.ORG (Cedric Ramsey) writes:
|> Hello peoplekind. I have a question about the behavior of the
|> signal function. Firstly, I want to trap the control-c, break,
|> and other interrupt keys the user may use to stop a program.
|> I did this by ;
|> 
|> main()
|> {
|>   signal (SIGINT, (*handler1) ());
|>   signal (SIGQUIT, (*handler2) ());
|>   ... 
|> }
|> 
|> 
|> But, when I type a control-c the program handles the signal as
|> expected; however, when I type the control-c a second time the program 
|> doesn't catch it and simply exits. 

I quote from K&R, p. 255:

"When a signal 'sig' subsequently occurs, the signal is __restored to its
default behavior__; then the signal-handler is called, as if by (*handler)(sig)."

The signal handler should reinstall itself before returning.  signal() apparently
does not act this way in my implementation (SunOS)...  Fortunately.

-- 
Here is the address to complain to:
pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD CIS: 70016,1355
That address again,
sync@thumper.princeton.edu PLink:OHS738 GEnie:OHS738 CIS: 4128 143 1234 937

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (09/28/90)

In article <2901@idunno.Princeton.EDU> pfalstad@bow.Princeton.EDU (Paul John Falstad) writes:
>In article <1990Sep28.120043.17628@NCoast.ORG>, ramsey@NCoast.ORG (Cedric Ramsey) writes:
>|> Hello peoplekind. I have a question about the behavior of the
>|> signal function. Firstly, I want to trap the control-c, break,
>|> and other interrupt keys the user may use to stop a program.
>|> I did this by ;
>|> 
>|> main()
>|> {
>|>   signal (SIGINT, (*handler1) ());
>|>   signal (SIGQUIT, (*handler2) ());
>|>   ... 
>|> }
>|> 
>|> 
>|> But, when I type a control-c the program handles the signal as
>|> expected; however, when I type the control-c a second time the program 
>|> doesn't catch it and simply exits. 
>
>I quote from K&R, p. 255:
>
>"When a signal 'sig' subsequently occurs, the signal is __restored to its
>default behavior__; then the signal-handler is called, as if by (*handler)(sig)."

Ahh... But Paul, don't we want to give him the answer to his question? Too many
times K & R has been quoted...and yet no real solutions are given.

>
>The signal handler should reinstall itself before returning. signal() 
>apparently does not act this way in my implementation (SunOS)...  Fortunately.

But programming should be PORTABLE, should it not :-)

A solution is suggested in "UNIX programming", by some author whom I've 
forgotten (a Howard SAMS publication).

What you should put in your signal handlers (*handler1), (*handler2),
is a simple 
signal(SIGINT, SIG_DFL); 
/* replace SIGINT by whatever signal you wish to trap */

This will restore the signal to previous status.

>-- 
>Here is the address to complain to:
>pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD CIS: 70016,1355
>That address again,
>sync@thumper.princeton.edu PLink:OHS738 GEnie:OHS738 CIS: 4128 143 1234 937

Or a simple "F" to alt.dev.null :-)


			-Kartik



(I need a new .signature -- any suggestions?)
subbarao@{phoenix or gauguin}.Princeton.EDU -|Internet
kartik@silvertone.Princeton.EDU (NeXT mail)       -|	
SUBBARAO@PUCC.BITNET			          - Bitnet

pfalstad@dae.Princeton.EDU (Paul John Falstad) (09/28/90)

In article <2905@idunno.Princeton.EDU> subbarao@phoenix.Princeton.EDU (Kartik Subbarao) writes:
>In article <2901@idunno.Princeton.EDU> pfalstad@bow.Princeton.EDU (Paul John Falstad) writes:
>>In article <1990Sep28.120043.17628@NCoast.ORG>, ramsey@NCoast.ORG (Cedric Ramsey) writes:
>>|> main()
>>|> {
>>|>   signal (SIGINT, (*handler1) ());
>>|>   signal (SIGQUIT, (*handler2) ());
>>|>   ... 
>>|> }
>>|> But, when I type a control-c the program handles the signal as
>>|> expected; however, when I type the control-c a second time the program 
>>|> doesn't catch it and simply exits. 
>>I quote from K&R, p. 255:
>>
>>"When a signal 'sig' subsequently occurs, the signal is __restored to its
>>default behavior__; then the signal-handler is called, as if by (*handler)(sig)."
>Ahh... But Paul, don't we want to give him the answer to his question? Too many
>times K & R has been quoted...and yet no real solutions are given.

I did answer his question.  Oh, sorry, you wanted a code fragment I
suppose.  Ok:

void handler1(whatever)
{
	printf("You're not getting out so easily!\n");
	signal(SIGINT,handler1);  /*  (*handler1) () not necessary */
}

This code implements the following sentence.

>>The signal handler should reinstall itself before returning. signal() 

>>apparently does not act this way in my implementation (SunOS)...  Fortunately.
>
>But programming should be PORTABLE, should it not :-)

True.  Why are you telling me this?  My above answer is portable.  I was
just commenting on the fact that SunOS does not implement signal this
way.

>What you should put in your signal handlers (*handler1), (*handler2),
>is a simple 
>signal(SIGINT, SIG_DFL); 
>This will restore the signal to previous status.

Thank you!  You have just found a portable way to implement the bug that
the original poster wanted to fix.  Now it doesn't work on nearly ALL
implementations of C instead of merely ANSI compliant ones.

Next time, read the article before following up to it.

>>Here is the address to complain to:
>Or a simple "F" to alt.dev.null :-)

Why didn't you then?

>(I need a new .signature -- any suggestions?)

Disclaimer: I have for a long time been suffering from a species of brain
injury which I incurred during the rigors of childbirth; and I'd like to
conclude by putting my finger up my nose.

How's that?  ;-)

--
Here is the address to complain to:
pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD CIS: 70016,1355
That address again,
sync@thumper.princeton.edu PLink:OHS738 GEnie:OHS738 CIS: 4128 143 1234 937

volpe@underdog.crd.ge.com (Christopher R Volpe) (09/29/90)

In article <2905@idunno.Princeton.EDU>, subbarao@phoenix.Princeton.EDU
(Kartik Subbarao) writes:
|>In article <2901@idunno.Princeton.EDU> pfalstad@bow.Princeton.EDU
(Paul John Falstad) writes:
|>>In article <1990Sep28.120043.17628@NCoast.ORG>, ramsey@NCoast.ORG
(Cedric Ramsey) writes:
|>>|> Hello peoplekind. I have a question about the behavior of the
|>>|> signal function. Firstly, I want to trap the control-c, break,
|>>|> and other interrupt keys the user may use to stop a program.
|>>|> I did this by ;
|>>|> 
|>>|> main()
|>>|> {
|>>|>   signal (SIGINT, (*handler1) ());
|>>|>   signal (SIGQUIT, (*handler2) ());
|>>|>   ... 
|>>|> }
|>>|> 
|>>|> 
|>>|> But, when I type a control-c the program handles the signal as
|>>|> expected; however, when I type the control-c a second time the program 
|>>|> doesn't catch it and simply exits. 

Isn't the above call to signal messed up to begin with? He is INVOKING
the handler itself and using the return value as the argument to
"signal". Shouldn't he just be passing "handler1" and "handler2", i.e.,
the *addresses* of the functions? Shouldn't the code read:
main()
{
  signal(SIGINT,handler1);
  signal(SIGQUIT,handler2);
}
                                                            
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (09/29/90)

There is a difference between AT&T and BSD signal calls (that has already been
hinted at) that is important to know in this situation:

When you set-up a signal handler in the AT&T universe, your handler
is only called the very next time that signal is caught and subsequent
calls refer back to the default handler unless you reset your handler
in the handler-code.

When you set up a signal handler in the BSD universe, your handler
is called for all subsequent trappings of that signal unless you
specifically reset the handler to be something else in the handler-code.

The following code fragment might be used to set up a minimal
Control-C handler that would be portable accross Unixes (assuming that
"att_universe" is #defined for an AT&T system and "ucb_universe" is 
#defined for a BSD system):

	#include <stdio.h>
	#include <signal.h>

	void ctrl_c_handler()
	{
	  printf( "\n+++ in ctrl_c_handler() +++\n" );

	#ifdef att_universe
		/* need to reset this handler so we can trap the signal again */
	  if ( signal( SIGINT, ctrl_c_handler ) < 0 )
	    perror( "unable to set-up SIGINT handler" );
	#endif

	}

	main()
	{
	  if ( signal( SIGINT, ctrl_c_handler ) < 0 )
	    perror( "unable to set-up SIGINT handler" );

	  printf( "about to loop forever\n\n" );
	  while (1);
	}


Anybody know about DOS and/or VMS???
______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~

cpcahil@virtech.uucp (Conor P. Cahill) (09/29/90)

In article <1990Sep28.120043.17628@NCoast.ORG> ramsey@NCoast.ORG (Cedric Ramsey) writes:
>main()
>{
>  signal (SIGINT, (*handler1) ());
>  signal (SIGQUIT, (*handler2) ());

On initial inspection I would say there was a problem with your call to signal.
This is probably due to the fact that you left off some important code. 
Normally the signal would be used as follows:

	main()
	{
		int	handler1();
		int	handler2();

		(void) signal(SIGINT,handler1);
		(void) signal(SIGQUIT,handler2);


Anyway, on to the real problem....

>But, when I type a control-c the program handles the signal as
>expected; however, when I type the control-c a second time the program 
>doesn't catch it and simply exits. 

To solve this problem you have to know that whenever a signal is caught
the action for that signal is automatically reset to the default state.
To fix this you must call signal() each time the handler is executed.

For example,

handler1(sig)
	int	sig;
{
	signal(sig,handler1);
	.
	.
	.


-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

cpcahil@virtech.uucp (Conor P. Cahill) (09/29/90)

In article <2901@idunno.Princeton.EDU> pfalstad@bow.Princeton.EDU (Paul John Falstad) writes:
>
>The signal handler should reinstall itself before returning. 

Actually the signal handler should reinstall itself immediatly (i.e. the first
thing it does) otherwise the receipt during the execution of the handler may
cause grief.  Even doing it as the first thing in the handler may not be
fast enough to ensure that another signal does not interrupt the program.  

That is why old System V signals should not be used for interprocess 
communications unless the rate of signals is guarranteed to be low.


-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

ramsey@NCoast.ORG (Cedric Ramsey) (09/30/90)

In article <12253@crdgw1.crd.ge.com> volpe@underdog.crd.ge.com (Christopher R Volpe) writes:
>In article <2905@idunno.Princeton.EDU>, subbarao@phoenix.Princeton.EDU
>(Kartik Subbarao) writes:
>|>In article <2901@idunno.Princeton.EDU> pfalstad@bow.Princeton.EDU
>(Paul John Falstad) writes:
>|>>In article <1990Sep28.120043.17628@NCoast.ORG>, ramsey@NCoast.ORG
>(Cedric Ramsey) writes:
>|>>|> Hello peoplekind. I have a question about the behavior of the
>|>>|> signal function. Firstly, I want to trap the control-c, break,
>|>>|> and other interrupt keys the user may use to stop a program.
>|>>|> I did this by ;
>|>>|> 
>|>>|> main()
>|>>|> {
>|>>|>   signal (SIGINT, (*handler1) ());
>|>>|>   signal (SIGQUIT, (*handler2) ());
>|>>|>   ... 
>|>>|> }
>|>>|> 
>|>>|> 
>|>>|> But, when I type a control-c the program handles the signal as
>|>>|> expected; however, when I type the control-c a second time the program 
>|>>|> doesn't catch it and simply exits. 
>
>Isn't the above call to signal messed up to begin with? He is INVOKING
>the handler itself and using the return value as the argument to
>"signal". Shouldn't he just be passing "handler1" and "handler2", i.e.,
>the *addresses* of the functions? Shouldn't the code read:
>main()
>{
>  signal(SIGINT,handler1);
>  signal(SIGQUIT,handler2);
>}
>                                                            
>==================
>Chris Volpe
>G.E. Corporate R&D
>volpecr@crd.ge.com

Oh, i'm sorry, please excuse me. I met to pass a pointer to a function namely,
signal(SIGINT, handler1);
signal(SIGQUIT, handler2);
I was thinking about function prototypes when I goofed there, an ansi c lint
checker would have caught it at compile though, but that's okay; I'm willing 
to take the flame for it; a minimum price for knowledge, hey.

Thankyou 4 your support.

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%% Ignorance is the lack of knowledge, now you know ! ;-)  %%
	%%                                                         %% 
	%% Cedric A. Ramsey                                        %% 
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%