help with signals

Daniel Wu dwu at nunki.usc.edu
Thu Feb 16 14:31:10 AEST 1989


I have 2 simple questions about signals...which may get a little involved:

  1. How do you tell which signal has been sent from within the signal
     handler?

     Instead of typing
	if ( signal(SIGINT,SIG_IGN) != SIG_IGN )
	   signal(SIGINT,sig_catch1);

	if ( signal(SIGQUIT,SIG_IGN) != SIG_IGN )
	   signal(SIGQUIT,sig_catch2);

	if ( signal(SIGHUP,SIG_IGN) != SIG_IGN )
	   signal(SIGHUP,sig_catch3);
	   .
	   .
	   .
     for each signal, defining an individual
     handler to process a particular signal, I was thinking of doing 
     something along these lines:
     
	u_short si_arr[]= {SIGINT,SIGQUIT,SIGHUP,...};

        for ( i=0; i < MAX_SIGNO; i++ )
	    if ( signal(sig_arr[i],sig_catch) != SIG_IGN )
	       signal(sig_arr[i],sig_catch);

     and then in the function sig_catch(),
	
      sig_catch()
      {
	switch( signal_no ) {	/* whatever signal_no is */
	  case SIGINIT:
	     /* do something */
	     break;
	  case SIGQUIT:
	     /* do something more */
	     break;
          case SIGHUP:
	     /* and then some */
          default:
        }
      }
    Now, I did RTFM, or at least read signal(3), so I know I can declare
      sig_catch(signal_no,code,scp,addr)
      int signal_no,code;
      struct sigcontext *scp;
      char *addr;
      {
         switch( signal_no ) {	/* and indeed, this works! */
				/* I get the right signal number */
	   case SIGINT:		/* But now if I try to call signal again*/
	      signal(SIGINT,SIG_IGN);
	      break;		/* This WON'T work */
				/* When I try to compile, I get a improper 
					function error */
	   default:
	      break;
      }
    As long as I don't try to call signal() agian, my code compiles and runs
    just fine, but no matter if I try
	 	signal(SIGINT,sig_catch);
    or 		signal(SIGINT,SIG_IGN);
    I can't get the program to compile.  Why is this, and what should I do?
    Alternately, can I find out what signal was delivered, without declaring
    those signal_no,code,scp,addr arguments?

 2. How do you reset the signal mask so that wait() will continue to wait for 
    the child to finish, after a signal interrupts the parent?
    Here's what I mean:  I do a

	ppid = getpid();		/* parent's pid*/
	setjmp(reset_pt);
        if ( ppid != getpid() )		/* kill all child processes */
           exit();
	if ( signal(SIGINT,SIG_IGN) != SIG_IGN )
           signal(sigarr[i],sig_catch);
		.
		.
		.
	if ( !(cpid1=fork()) ) {	/* child 1 */
	   /* do something */
	   exit(0);
        }
	if ( !(cpid2=fork()) ) {	/* child 2 */
	   /* do something */
	   exit(0);
        }
	wait(&status);		/* for a child to finish */
	wait(&status);		/* for the other child to finish*/
  }

  sig_catch()
  {
	longjmp(reset_pt);
  }

Now let's say I start the program up, and let it advance to the wait()
calls. (The child processes take a long time to complete).  I hit ^C,
and all 3 processes longjmp to the reset_pt.  There, the children get
nuked, and only the parent process survives---to fork() off the second
generation of children.  However, when the parent hits the wait() statments,
it slips through!  I believe wait() is reading the exit signal of the
deceased children, not the newly hatched ones. How can I reset the signal
mask that wait() reads, so that wait() ignores the exit signal of the
first 2 child processes? 

Actually, I already do have a fix for this.  I do:
	while ( (pid=wait(&status)) != cpid1 && pid != -1 )
	  ;
	while ( (pid=wait(&status)) != cpid2 && pid != -1 )
	  ;
which works as intended.  However, I would like to understand the details
of how signals work, and how I could have resolved the wait() problem
without embedding it in the while loop.  I've tried reading sigvec(3)
for futher information, but I couldn't make heads or tails of it.

Can please someone help me?


Daniel
dwu at castor.usc.edu



More information about the Comp.unix.questions mailing list