Signal

The terminal-generated signals occur when users press certain terminal keys. Pressing the DELETE key on the terminal (or Control-C on many systems) normally causes the interrupt signal (SIGINT) to be generated. This is how to stop a runaway program.

  1. Terminal generated
  2. Hardware exceptions generate signals: divide by 0, invalid memory reference, and the like. These conditions are usually detected by the hardware, and the kernel is notified. The kernel then generates the appropriate signal for the process that was running at the time the condition occurred. For example, SIGSEGV is generated for a process that executes an invalid memory reference
  3. The kill(2) function allows a process to send any signal to another process or process group. Naturally, there are limitations: we have to be the owner of the process that we’re sending the signal to, or we have to be the superuser
  4. The kill(1) command allows us to send signals to other processes. This program is just an interface to the kill function. This command is often used to terminate a runaway background process.
  5. Software conditions can generate signals when a process should be notified of various events. These aren’t hardware-generated conditions (as is the divideby- 0 condition), but software conditions. Examples are SIGURG (generated when out-of-band data arrives over a network connection), SIGPIPE (generated when a process writes to a pipe that has no reader), and SIGALRM (generated when an alarm clock set by the process expires).

We can tell the kernel to do one of three things when a signal occurs. We call this the disposition of the signal, or the action associated with a signal.

  1. Ignore the signal. This works for most signals, but two signals can never be ignored: SIGKILL and SIGSTOP. The reason these two signals can’t be ignored is to provide the kernel and the superuser with a surefire way of either killing or stopping any process. Also, if we ignore some of the signals that are generated by a hardware exception (such as illegal memory reference or divide by 0), the behavior of the process is undefined.
  2. Catch the signal. To do this, we tell the kernel to call a function of ours whenever the signal occurs. In our function, we can do whatever we want to handle the condition. If we’re writing a command interpreter, for example, when the user generates the interrupt signal at the keyboard, we probably want to return to the main loop of the program, terminating whatever command we were executing for the user. If the SIGCHLD signal is caught, it means that a child process has terminated, so the signal-catching function can call waitpid to fetch the child’s process ID and termination status. As another example, if the process has created temporary files, we may want to write a signal-catching function for the SIGTERM signal (the termination signal that is the default signal sent by the kill command) to clean up the temporary files. Note that the two signals SIGKILL and SIGSTOP can’t be caught.
  3. Let the default action apply. Every signal has a default action. Note that the default action for most signals is to terminate the process.

Unix system signal

core file

_core _in last table means a core dump file will be generated during associated signals be captured.

How generate the core dump file.

$ ulimit -c unlimited

How read this core dump file.

gdb binary-file core-file

Some important signals

  • SIGABRT
    This signal is generated by calling the abort function

  • SIGALRM
    This signal is generated when a timer set with the alarm function timeout.

  • SIGBUS
    This signal indicate an implementation-defined hardware fault .

  • SIGCHLD
    Whenever a process terminates or stops, the SIGCHLD signal is sent to the parent. By default, this signal is ignored, so the parent must catch this signal if it wants to be notified whenever a child’s status changes. The normal action in the signal catching function is to call one of the wait functions to fetch the child’s process ID and termination status.

  • SIGHUP
    This signal is sent to the controlling process (session leader) associated with a cntrolling terminal if a disconnect is detected by the terminal interface.This signal is also generated if the session leader terminates. In this case, the signal is sent to each process in the foreground process group. This signal is commonly used to notify daemon processes to reread their configuration files. The reason SIGHUP is chosen for this task is that a daemon should not have a controlling terminal and would normally never receive this signal.

  • SIGINT

    This signal is generated by the terminal driver when we press the interrupt key \(often DELETE or Control-C\). This signal is sent to all processes in the foreground process group

  • SIGQUIT

    signal is generated by the terminal driver when we press the terminal quit key \(often Control-backslash\). This signal is sent to all processes in the foreground process group . This signal not only terminates the foreground process group \(as does SIGINT\), but also generates a core file.

  • SIGKILL

    This signal is one of the two that can’t be caught or ignored. It provides the system administrator with a sure way to kill any process.

  • SIGSEGV

    This signal indicates that the process has made an invalid memory reference (which is usually a sign that the program has a bug, such as dereferencing an uninitialized pointer).

  • SIGTERM VS SIGKILL

https://major.io/2010/03/18/sigterm-vs-sigkill/

Unreliable Signal

The earlier version of the unix system, signals were unreliable, these mainly involve three issues.

  1. Signal maybe get lost
  2. The action of a signal was reset to its default each time the signal occurred.
  3. The process unable turn the signal off

Interrupted System Call

A characteristic of earlier UNIX systems was that if a process caught a signal while the process was blocked in a ‘‘slow’’ system call, the system call was interrupted. The system call returned an error and errno was set to EINTR. Some of these slow system call includes read, write, open, pause etc.

However

To prevent applications from having to handle interrupted system calls, 4.2BS D introduced the automatic restarting of certain interrupted system calls. The system calls that were automatically restarted are ioctl, read, readv, write, writev, wait, and
waitpid. So on most of the modern system, we need not specially handle EINTR error during read or write called.

Reentrant Function

What is reentrant function?

The functions that are guaranteed to be safe to call from within a signal handler. These functions are reentrant and are called async-signal safe by the Single UNIX Specification. Besides being reentrant, they block any signals during operation if delivery of a signal might cause inconsistencies. A reentrant function can be invoked, interrupted, and re-invoked.

How write reentrant function?

  1. Do not use static or global data structures.

  2. Do not call malloc or free

  3. Do not use standard I/O library.Most implementations of the standard I/O library use global data structures in a nonreentrant way(include printf)

  4. Do not self-modify code

Some other explanation about reentrant function

https://www.quora.com/When-is-a-function-reentrant-How-does-that-relate-to-it-being-thread-safe

http://stackoverflow.com/questions/2799023/what-exactly-is-a-reentrant-function

https://www.ibm.com/developerworks/linux/library/l-reent/index.html#N101CA

Reentrant functions that can be called from signal function.

Be aware that, as a general rule, when calling the functions listed in above Figure from a signal handler, we should save and restore errno.

Sigaction Function

#include <signal.h>


int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);


//Returns: 0 if OK, −1 on error
struct sigaction {

    void (*sa_handler)(int);     /* addr of signal handler, */
                                 /* or SIG_IGN, or SIG_DFL */

    sigset_t sa_mask;            /* additional signals to block */

    int sa_flags;                /* signal options, Figure 10.16 */


    /* alternate handler */

    void (*sa_sigaction)(int, siginfo_t *, void *);
};

sa_mask

The sa_mask field specifies a set of signals that are added to the signal mask of the process before the signal-catching function is called. If and when the signal-catching function returns, the signal mask of the process is reset to its previous value.

Some features of sa_mask introduced.

  1. Whenever we are processing a given signal, another occurrence of that same signal is blocked until we’re finished processing the first occurrence.
  2. If the signal occurs five times while it is blocked, when we unblock the signal, the signal-handling function for that signal will usually be invoked only one time.
  3. Once we install an action for a given signal, that action remains installed until we explicitly change it by calling sigaction. Unlike earlier systems with their unreliable signals, POSIX.1 requires that a signal handler remain installed until explicitly changed

sigsuspend

sigsuspend = sigprocmask(unblock) + pause()

And there is time window between sigprocmask(unblock) and paused, may caused signal be missed and pause indefinitely. sigsuspend make these two function call be a atomic operation.

Three classic scenario that use sigsuspend.

  1. Protect critical regions of code that we don’t want interrupted by a signal.
  2. Wait for a signal handler to set a global variable
  3. Signals can be used to synchronize a parent and child

kill, abort, raise

abort() = raise(SIGABORT)

raise(signum) = kill(getpid(), signum)

abort() = kill(getpid(), SIGABORT)

results matching ""

    No results matching ""