Annotation of 43BSDReno/share/doc/ps2/03.uprog/p6, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.