cdash@boulder.Colorado.EDU (Charles Shub) (03/05/88)
on at&t unix if a system call to (eg) read is in progress when a signal occurs, the system call fails. On sun unix and ultrix, the system call restarts. On the sun, one can use siginterrupt(3) to make the system call fail. How do I make the system call fail under ultrix??????? we are running 1.2 on microvaxen. -- cdash aka cdash@boulder.colorado.edu aka ...hao!boulder!cdash aka ...nbires!boulder!cdash aka (303) 593-3492
wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (03/06/88)
In article <1583@boulder.Colorado.EDU> cdash@boulder.Colorado.EDU (Charles Shub) writes: >on at&t unix if a system call to (eg) read is in progress when a signal >occurs, the system call fails. On sun unix and ultrix, the system call >restarts. On the sun, one can use siginterrupt(3) to make the system call >fail. How do I make the system call fail under ultrix??????? Another (hack) way to do this involves a setjump/longjump pair. Put a setjump around the system call, set a signal handler for the signal in question, and finally put a longjump in the signal handler to the setjump saved point. (Don't forget to take down the signal handler after use, or else you will find yourself longjumping back to the same section of code everytime a signal of that type comes in.) -- Wolfgang Rupprecht ARPA: wolfgang@mgm.mit.edu (IP 18.82.0.114) 326 Commonwealth Ave. UUCP: mit-eddie!mgm.mit.edu!wolfgang Boston, Ma. 02115 TEL: (617) 267-4365
simon@its63b.ed.ac.uk (Simon Brown) (03/07/88)
In article <1583@boulder.Colorado.EDU> cdash@boulder.Colorado.EDU (Charles Shub) writes: >on at&t unix if a system call to (eg) read is in progress when a signal >occurs, the system call fails. On sun unix and ultrix, the system call >restarts. On the sun, one can use siginterrupt(3) to make the system call >fail. How do I make the system call fail under ultrix??????? >we are running 1.2 on microvaxen. A particularly disgusting way to do this is to close(2) the descriptor being read from inside the signal-handling routine, keeping a dup(2)'d copy so you can restore it later. The read(2) cannot restart on a closed descriptor, so it fails (with errno==EBADF). I'm sure there must be a better way (though it probably isn't so portable :-)): extern int descriptor; static int dupdescriptor; handler() { dup2(descriptor, dupdescriptor); close(descriptor); } readchar() { char ch; switch (read(descriptor,&ch,1)) { case -1: if (errno == EBADF) { descriptor = dupdescriptor; return(INTERRUPTED); } else return(...); case 0: return(EOF); default: return(ch); } } -- -- -------------------------------------------------- | Simon Brown | | Laboratory for Foundations of Computer Science | | Department of Computer Science | | University of Edinburgh, Scotland, UK. | -------------------------------------------------- UUCP: uunet!mcvax!ukc!lfcs!simon ARPA: simon%lfcs.ed@nss.cs.ucl.ac.uk "Life's like that, you know" JANET: simon@uk.ac.ed.lfcs
news@oberon.USC.EDU (USENET News) (02/16/89)
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@castor.usc.edu ================================================================= Daniel Wu ARPA: dwu@castor.usc.edu UUCP: ? dwu@castor.UUCP ? I'm not very familiar with the backbone sites this machine's connected to. Somebody, please send me a diagram of major gateways. =================================================================
dwu@nunki.usc.edu (Daniel Wu) (02/16/89)
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@castor.usc.edu
guy@auspex.UUCP (Guy Harris) (02/18/89)
> Alternately, can I find out what signal was delivered, without declaring > those signal_no,code,scp,addr arguments? Not without declaring "signal_no", but you can blow off the other three arguments. You can just do sig_catch(signal_no) int signal_no; which all sufficiently modern UNIX implementations should support. The fact that the manual page mentions other arguments merely indicates that the implementors have made it possible for handlers to be declared with the extra arguments and that, for some signals in some circumstances, those arguments will have meaningful (and possibly useful) values, not that it won't work if you declare the function with only one argument. (If they couldn't make it work regardless of whether you declared it with only one "int" argument or all the arguments, they'd better have provided a different mechanism for giving you the other arguments, since they'll break one hell of a lot of code otherwise. Fortunately, from the appearance of the "addr" argument, you're probably working on a Sun - or a Solbourne :-) - in which case I know it works either way.) (BTW, note that the SVID, issue 2, actually allows for extra arguments; on page 123 in SIGNAL(BA_OS), it says: ...Additional arguments may be passed to the signal-catching function for hardware-generated signals. ) >How can I reset the signal mask that wait() reads, so that wait() >ignores the exit signal of the first 2 child processes? You can't. "wait" *doesn't* read the signal mask. >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. That is the correct way to do what you want.