Unix Signals.docx

  • Upload
    ismimi

  • View
    214

  • Download
    0

Embed Size (px)

Citation preview

  • 7/28/2019 Unix Signals.docx

    1/5

    Introduction To Unix Signals Programming

    What Are Signals?

    Signals, to be short, are various notifications sent to a process in order to notify it of various"important" events. By their nature, they interrupt whatever the process is doing at this minute,

    and force it to handle them immediately. Each signal has an integer number that represents it (1,

    2 and so on), as well as a symbolic name that is usually defined in the file /usr/include/signal.h or

    one of the files included by it directly or indirectly (HUP, INT and so on. Use the command 'kill

    -l' to see a list of signals supported by your system).

    Each signal may have a signal handler, which is a function that gets called when the process

    receives that signal. The function is called in "asynchronous mode", meaning that no where in

    your program you have code that calls this function directly. Instead, when the signal is sent to

    the process, the operating system stops the execution of the process, and "forces" it to call the

    signal handler function. When that signal handler function returns, the process continuesexecution from wherever it happened to be before the signal was received, as if this interruption

    never occurred.

    signals are very similar in their behavior to hardware interruptions. The difference is that while

    interrupts are sent to the operating system by the hardware, signals are sent to the process by theoperating system, or by other processes. Note that signals have nothing to do with software

    interrupts, which are still sent by the hardware (the CPU itself, in this case).

    Sending Signals To Processes

    Sending Signals Using The Keyboard

    The most common way of sending signals to processes is using the keyboard. There are certainkey presses that are interpreted by the system as requests to send signals to the process with

    which we are interacting:

    Ctrl-C

    Pressing this key causes the system to send an INT signal (SIGINT) to the runningprocess. By default, this signal causes the process to immediately terminate.

    Ctrl-Z

    Pressing this key causes the system to send a TSTP signal (SIGTSTP) to the runningprocess. By default, this signal causes the process to suspend execution.

    Ctrl-\

    Pressing this key causes the system to send an ABRT signal (SIGABRT) to the runningprocess. By default, this signal causes the process to immediately terminate. Note thatthis redundancy (i.e. Ctrl-\ doing the same as Ctrl-C) gives us some better flexibility.

  • 7/28/2019 Unix Signals.docx

    2/5

    Sending Signals From The Command Line

    Another way of sending signals to processes is done using various commands, usually internal to

    the shell:

    kill The kill command accepts two parameters: a signal name (or number), and a process ID.

    Usually the syntax for using it goes something like:

    kill -

    For example, in order to send the INT signal to process with PID 5342, type:

    kill -INT 5342

    This has the same affect as pressing Ctrl-C in the shell that runs that process.

    If no signal name or number is specified, the default is to send a TERM signal to theprocess, which normally causes its termination, and hence the name of the killcommand.

    fg

    On most shells, using the 'fg' command will resume execution of the process (that was

    suspended with Ctrl-Z), by sending it a CONT signal.

    Sending Signals Using System Calls

    A third way of sending signals to processes is by using the kill system call. This is the normal

    way of sending a signal from one process to another. This system call is also used by the 'kill'command or by the 'fg' command. Here is an example code that causes a process to suspend its

    own execution by sending itself the STOP signal:

    #include /* standard unix functions, like getpid() */#include /* various type definitions, like pid_t */#include /* signal name macros, and the kill() prototype */

    /* first, find my own process ID */pid_t my_pid = getpid();

    /* now that i got my PID, send myself the STOP signal. */

    kill(my_pid, SIGSTOP);An example of a situation when this code might prove useful, is inside a signal handler that

    catches the TSTP signal (Ctrl-Z, remember?) in order to do various tasks before actually

    suspending the process. We will see an example of this later on.

    Catching Signals - Signal Handlers

  • 7/28/2019 Unix Signals.docx

    3/5

    Catchable And Non-Catchable Signals

    Most signals may be caught by the process, but there are a few signals that the process cannot

    catch, and cause the process to terminate. For example, the KILL signal (-9 on all unices I've metso far) is such a signal. This is why you usually see a process being shut down using this signal if

    it gets "wild". One process that uses this signal is a system shutdown process. It first sends a

    TERM signal to all processes, waits a while, and after allowing them a "grace period" to shut down

    cleanly, it kills whichever are left using the KILL signal.

    STOP is also a signal that a process cannot catch, and forces the process's suspension

    immediately. This is useful when debugging programs whose behavior depends on timing.

    Suppose that process A needs to send some data to process B, and you want to check some

    system parameters after the message is sent, but before it is received and processed by process B.

    One way to do that would be to send a STOP signal to process B, thus causing its suspension, and

    then running process A and waiting until it sends its oh-so important message to process B. Nowyou can check whatever you want to, and later on you can use the CONT signal to continue

    process B's execution, which will then receive and process the message sent from process A.

    Now, many other signals are catchable, and this includes the famous SEGV and BUS signals. You

    probably have seen numerous occasions when a program has exited with a message such as

    'Segmentation Violation - Core Dumped', or'Bus Error - core dumped'. In the first occasion, a

    SEGV signal was sent to your program due to accessing an illegal memory address. In the second

    case, a BUS signal was sent to your program, due to accessing a memory address with invalidalignment. In both cases, it is possible to catch these signals in order to do some cleanup - kill

    child processes, perhaps remove temporary files, etc. Although in both cases, the memory used

    by your process is most likely corrupt, it's probable that only a small part of it was corrupt, socleanup is still usually possible.

    Default Signal Handlers

    If you install no signal handlers of your own (remember what a signal handler is? yes, that

    function handling a signal?), the runtime environment sets up a set of default signal handlers for

    your program. For example, the default signal handler for the TERM signal calls the exit()

    system call. The default handler for the ABRT signal calls the abort() system call, which causes

    the process's memory image to be dumped into a file named 'core' in the process's currentdirectory, and then exit.

    Installing Signal Handlers

  • 7/28/2019 Unix Signals.docx

    4/5

    There are several ways to install signal handlers. We'll use the most basic form here, and refer

    you to your manual pages for further reading.

    The signal() System Call

    The signal() system call is used to set a signal handler for a single signal type. signal()accepts a signal number and a pointer to a signal handler function, and sets that handler to accept

    the given signal. As an example, here is a code snippest that causes the program to print the

    string "Don't do that" when a user presses Ctrl-C:

    #include /* standard I/O functions */#include /* standard unix functions, like getpid() */#include /* various type definitions, like pid_t */

    #include /* signal name macros, and the signal() prototype */

    /* first, here is the signal handler */void catch_int(int sig_num){

    /* re-set the signal handler again to catch_int, for next time */signal(SIGINT, catch_int);/* and print the message */printf("Don't do that");fflush(stdout);

    }

    .

    .

    ./* and somewhere later in the code.... */..

    /* set the INT (Ctrl-C) signal handler to 'catch_int' */signal(SIGINT, catch_int);

    /* now, lets get into an infinite loop of doing nothing. */for ( ;; )

    pause();

    Notes:

    the pause() system call causes the process to halt execution, until a signal is received. itis surely better then a 'busy wait' infinite loop.

    the name of a function in C/C++ is actually a pointer to the function, so when you'reasked to supply a pointer to a function, you may simply specify its name instead.

    On some systems (such as Linux), when a signal handler is called, the systemautomatically resets the signal handler for that signal to the default handler. Thus, we re-

  • 7/28/2019 Unix Signals.docx

    5/5

    assign the signal handler immediately when entering the handler function. Otherwise, the

    next time this signal is received, the process will exit (default behavior forINT signals).Even on systems that do not behave in this way, it still won't hurt, so adding this line

    always is a good idea.

    Pre-defined Signal Handlers

    For our convenience, there are two pre-defined signal handler functions that we can use, instead

    of writing our own: SIG_IGN and SIG_DFL.

    SIG_IGN:Causes the process to ignore the specified signal. For example, in order to ignore Ctrl-C

    completely (useful for programs that must NOT be interrupted in the middle, or in criticalsections), write this:

    signal(SIGINT, SIG_IGN);

    SIG_DFL:

    Causes the system to set the default signal handler for the given signal (i.e. the samehandler the system would have assigned for the signal when the process started running):

    signal(SIGTSTP, SIG_DFL);