|
|
1.1 ! root 1: .\" @(#)p6 6.2 (Berkeley) 5/9/86 ! 2: .\" ! 3: .NH ! 4: SIGNALS \(em INTERRUPTS AND ALL THAT ! 5: .PP ! 6: This section is concerned with how to ! 7: deal gracefully with signals from ! 8: the outside world (like interrupts), and with program faults. ! 9: Since there's nothing very useful that ! 10: can be done from within C about program ! 11: faults, which arise mainly from illegal memory references ! 12: or from execution of peculiar instructions, ! 13: we'll discuss only the outside-world signals: ! 14: .IT interrupt , ! 15: which is sent when the ! 16: .UC DEL ! 17: character is typed; ! 18: .IT quit , ! 19: generated by the ! 20: .UC FS ! 21: character; ! 22: .IT hangup , ! 23: caused by hanging up the phone; ! 24: and ! 25: .IT terminate , ! 26: generated by the ! 27: .IT kill ! 28: command. ! 29: When one of these events occurs, ! 30: the signal is sent to ! 31: .IT all ! 32: processes which were started ! 33: from the corresponding terminal; ! 34: unless other arrangements have been made, ! 35: the signal ! 36: terminates the process. ! 37: In the ! 38: .IT quit ! 39: case, a core image file is written for debugging ! 40: purposes. ! 41: .PP ! 42: The routine which alters the default action ! 43: is ! 44: called ! 45: .UL signal . ! 46: It has two arguments: the first specifies the signal, and the second ! 47: specifies how to treat it. ! 48: The first argument is just a number code, but the second is the ! 49: address is either a function, or a somewhat strange code ! 50: that requests that the signal either be ignored, or that it be ! 51: given the default action. ! 52: The include file ! 53: .UL signal.h ! 54: gives names for the various arguments, and should always be included ! 55: when signals are used. ! 56: Thus ! 57: .P1 ! 58: #include <signal.h> ! 59: ... ! 60: signal(SIGINT, SIG_IGN); ! 61: .P2 ! 62: causes interrupts to be ignored, while ! 63: .P1 ! 64: signal(SIGINT, SIG_DFL); ! 65: .P2 ! 66: restores the default action of process termination. ! 67: In all cases, ! 68: .UL signal ! 69: returns the previous value of the signal. ! 70: The second argument to ! 71: .UL signal ! 72: may instead be the name of a function ! 73: (which has to be declared explicitly if ! 74: the compiler hasn't seen it already). ! 75: In this case, the named routine will be called ! 76: when the signal occurs. ! 77: Most commonly this facility is used ! 78: to allow the program to clean up ! 79: unfinished business before terminating, for example to ! 80: delete a temporary file: ! 81: .P1 ! 82: #include <signal.h> ! 83: ! 84: main() ! 85: { ! 86: int onintr(); ! 87: ! 88: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 89: signal(SIGINT, onintr); ! 90: ! 91: /* Process ... */ ! 92: ! 93: exit(0); ! 94: } ! 95: ! 96: onintr() ! 97: { ! 98: unlink(tempfile); ! 99: exit(1); ! 100: } ! 101: .P2 ! 102: .PP ! 103: Why the test and the double call to ! 104: .UL signal ? ! 105: Recall that signals like interrupt are sent to ! 106: .ul ! 107: all ! 108: processes started from a particular terminal. ! 109: Accordingly, when a program is to be run ! 110: non-interactively ! 111: (started by ! 112: .UL & ), ! 113: the shell turns off interrupts for it ! 114: so it won't be stopped by interrupts intended for foreground processes. ! 115: If this program began by announcing that all interrupts were to be sent ! 116: to the ! 117: .UL onintr ! 118: routine regardless, ! 119: that would undo the shell's effort to protect it ! 120: when run in the background. ! 121: .PP ! 122: The solution, shown above, is to test the state of interrupt handling, ! 123: and to continue to ignore interrupts if they are already being ignored. ! 124: The code as written ! 125: depends on the fact that ! 126: .UL signal ! 127: returns the previous state of a particular signal. ! 128: If signals were already being ignored, the process should continue to ignore them; ! 129: otherwise, they should be caught. ! 130: .PP ! 131: A more sophisticated program may wish to intercept ! 132: an interrupt and interpret it as a request ! 133: to stop what it is doing ! 134: and return to its own command-processing loop. ! 135: Think of a text editor: ! 136: interrupting a long printout should not cause it ! 137: to terminate and lose the work ! 138: already done. ! 139: The outline of the code for this case is probably best written like this: ! 140: .P1 ! 141: #include <signal.h> ! 142: #include <setjmp.h> ! 143: jmp_buf sjbuf; ! 144: ! 145: main() ! 146: { ! 147: int (*istat)(), onintr(); ! 148: ! 149: istat = signal(SIGINT, SIG_IGN); /* save original status */ ! 150: setjmp(sjbuf); /* save current stack position */ ! 151: if (istat != SIG_IGN) ! 152: signal(SIGINT, onintr); ! 153: ! 154: /* main processing loop */ ! 155: } ! 156: .P2 ! 157: .P1 ! 158: onintr() ! 159: { ! 160: printf("\enInterrupt\en"); ! 161: longjmp(sjbuf); /* return to saved state */ ! 162: } ! 163: .P2 ! 164: The include file ! 165: .UL setjmp.h ! 166: declares the type ! 167: .UL jmp_buf ! 168: an object in which the state ! 169: can be saved. ! 170: .UL sjbuf ! 171: is such an object; it is an array of some sort. ! 172: The ! 173: .UL setjmp ! 174: routine then saves ! 175: the state of things. ! 176: When an interrupt occurs, ! 177: a call is forced to the ! 178: .UL onintr ! 179: routine, ! 180: which can print a message, set flags, or whatever. ! 181: .UL longjmp ! 182: takes as argument an object stored into by ! 183: .UL setjmp , ! 184: and restores control ! 185: to the location after the call to ! 186: .UL setjmp , ! 187: so control (and the stack level) will pop back ! 188: to the place in the main routine where ! 189: the signal is set up and the main loop entered. ! 190: Notice, by the way, that ! 191: the signal ! 192: gets set again after an interrupt occurs. ! 193: This is necessary; most signals are automatically ! 194: reset to their default action when they occur. ! 195: .PP ! 196: Some programs that want to detect signals simply can't be stopped ! 197: at an arbitrary point, ! 198: for example in the middle of updating a linked list. ! 199: If the routine called on occurrence of a signal ! 200: sets a flag and then ! 201: returns instead of calling ! 202: .UL exit ! 203: or ! 204: .UL longjmp , ! 205: execution will continue ! 206: at the exact point it was interrupted. ! 207: The interrupt flag can then be tested later. ! 208: .PP ! 209: There is one difficulty associated with this ! 210: approach. ! 211: Suppose the program is reading the ! 212: terminal when the interrupt is sent. ! 213: The specified routine is duly called; it sets its flag ! 214: and returns. ! 215: If it were really true, as we said ! 216: above, that ``execution resumes at the exact point it was interrupted,'' ! 217: the program would continue reading the terminal ! 218: until the user typed another line. ! 219: This behavior might well be confusing, since the user ! 220: might not know that the program is reading; ! 221: he presumably would prefer to have the signal take effect instantly. ! 222: The method chosen to resolve this difficulty ! 223: is to terminate the terminal read when execution ! 224: resumes after the signal, returning an error code ! 225: which indicates what happened. ! 226: .PP ! 227: Thus programs which catch and resume ! 228: execution after signals should be prepared for ``errors'' ! 229: which are caused by interrupted ! 230: system calls. ! 231: (The ones to watch out for are reads from a terminal, ! 232: .UL wait , ! 233: and ! 234: .UL pause .) ! 235: A program ! 236: whose ! 237: .UL onintr ! 238: program just sets ! 239: .UL intflag , ! 240: resets the interrupt signal, and returns, ! 241: should usually include code like the following when it reads ! 242: the standard input: ! 243: .P1 ! 244: if (getchar() == EOF) ! 245: if (intflag) ! 246: /* EOF caused by interrupt */ ! 247: else ! 248: /* true end-of-file */ ! 249: .P2 ! 250: .PP ! 251: A final subtlety to keep in mind becomes important ! 252: when signal-catching is combined with execution of other programs. ! 253: Suppose a program catches interrupts, and also includes ! 254: a method (like ``!'' in the editor) ! 255: whereby other programs can be executed. ! 256: Then the code should look something like this: ! 257: .P1 ! 258: if (fork() == 0) ! 259: execl(...); ! 260: signal(SIGINT, SIG_IGN); /* ignore interrupts */ ! 261: wait(&status); /* until the child is done */ ! 262: signal(SIGINT, onintr); /* restore interrupts */ ! 263: .P2 ! 264: Why is this? ! 265: Again, it's not obvious but not really difficult. ! 266: Suppose the program you call catches its own interrupts. ! 267: If you interrupt the subprogram, ! 268: it will get the signal and return to its ! 269: main loop, and probably read your terminal. ! 270: But the calling program will also pop out of ! 271: its wait for the subprogram and read your terminal. ! 272: Having two processes reading ! 273: your terminal is very unfortunate, ! 274: since the system figuratively flips a coin to decide ! 275: who should get each line of input. ! 276: A simple way out is to have the parent program ! 277: ignore interrupts until the child is done. ! 278: This reasoning is reflected in the standard I/O library function ! 279: .UL system : ! 280: .P1 ! 281: #include <signal.h> ! 282: ! 283: system(s) /* run command string s */ ! 284: char *s; ! 285: { ! 286: int status, pid, w; ! 287: register int (*istat)(), (*qstat)(); ! 288: ! 289: if ((pid = fork()) == 0) { ! 290: execl("/bin/sh", "sh", "-c", s, 0); ! 291: _exit(127); ! 292: } ! 293: istat = signal(SIGINT, SIG_IGN); ! 294: qstat = signal(SIGQUIT, SIG_IGN); ! 295: while ((w = wait(&status)) != pid && w != -1) ! 296: ; ! 297: if (w == -1) ! 298: status = -1; ! 299: signal(SIGINT, istat); ! 300: signal(SIGQUIT, qstat); ! 301: return(status); ! 302: } ! 303: .P2 ! 304: .PP ! 305: As an aside on declarations, ! 306: the function ! 307: .UL signal ! 308: obviously has a rather strange second argument. ! 309: It is in fact a pointer to a function delivering an integer, ! 310: and this is also the type of the signal routine itself. ! 311: The two values ! 312: .UL SIG_IGN ! 313: and ! 314: .UL SIG_DFL ! 315: have the right type, but are chosen so they coincide with ! 316: no possible actual functions. ! 317: For the enthusiast, here is how they are defined for the PDP-11; ! 318: the definitions should be sufficiently ugly ! 319: and nonportable to encourage use of the include file. ! 320: .P1 ! 321: #define SIG_DFL (int (*)())0 ! 322: #define SIG_IGN (int (*)())1 ! 323: .P2
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.