Signal Processing Mechanism

Source: Internet
Author: User
Signal is a very important part in Linux programming. This article will introduce in detail the basic concepts of the signal mechanism, the general implementation of the signal mechanism in Linux, and how to use the signal, and several system calls related to signals.

The signal mechanism is a method for transmitting messages between processes. All signals are called Soft Interrupt signals, or soft interruptions. From its name, we can see that its essence and use are very interrupted. Therefore, signals are part of process control.

I. Basic concepts of Signals

This section first introduces some basic concepts of signals, and then provides some basic signal types and events corresponding to signals. Basic concepts are important for understanding and using signals. Next let's take a look at what a signal is.

1. Basic Concepts

The Soft Interrupt signal (signal) is used to notify the process of an asynchronous event. Processes can call kill to send Soft Interrupt signals to each other. The kernel can also send a signal to the process due to internal events to notify the process of an event. Note that the signal is only used to notify a process of events and does not transmit any data to the process.

Processes that receive signals have different processing methods for various signals. There are three types of processing methods: the first is an interrupt-like processing program. For signals to be processed, the process can specify a processing function for processing. The second method is to ignore a signal and do not process it any more, just as it has never happened. The third method is to retain the default value of the system for processing the signal. This default operation causes the process to terminate most of the default operations on the signal. A process calls signal to specify the process's processing behavior for a signal.

There is a soft interrupt signal field in the table of the Progress table. Each digit in the field corresponds to a signal. When a signal is sent to the process, it corresponds to a position. From this we can see that the process can retain different signals at the same time, but for the same signal, the process does not know how many signals have come before processing.

2. Signal type

There are many reasons for sending signals. Here we simply classify the reasons for sending signals to learn about various signals:

(1) signals related to process termination. This type of signal is sent when the process exits or the sub-process is terminated.
(2) signals related to process exception events. For example, if a process crosses the border, attempts to write a read-only memory area (such as the program body area), or executes a privileged command and other hardware errors.
(3) signals related to unrecoverable conditions during system calls. For example, when the system calls exec, the original resources have been released, and the system resources have been exhausted.
(4) signals related to non-predicted error conditions during system calls. For example, execute a non-existing system call.
(5) signals sent by processes in user mode. For example, a process call system calls kill to send signals to other processes.
(6) signals related to terminal interaction. For example, you can close a terminal or press the break Key.
(7) signal of process execution.

The signal list supported by Linux is as follows. Many signals are related to the machine's architecture. First, the signals listed in POSIX.1 are listed as follows:

Signal Value Processing
----------------------------------------------------------------------
SIGHUP 1 A terminal suspension or Control Process Termination
SIGINT 2 A keyboard interruption (for example, the break Key is pressed)
The exit key of the sigquit 3 C keyboard is pressed
Invalid SIGILL 4 C command
SIGABRT 6 C Exit Command issued by abort (3)
SIGFPE 8 C floating point exception
SIGKILL 9 AEF Kill signal
SIGSEGV 11 C Invalid Memory Reference
SIGPIPE 13 A pipe rupture: Write an pipe without A read Port
SIGALRM 14 A signal sent by alarm (2)
SIGTERM 15 A termination signal
SIGUSR1 30,10, 16 A user-defined signal 1
SIGUSR2, 17 A user-defined Signal 2
SIGCHLD, 18 B sub-process end signal
SIGCONT 19,18, 25 process continued (previously stopped process)
SIGSTOP 17,19, 23 DEF terminate the process
SIGTSTP 18, 20, 24 D control terminal (tty) press the stop key
SIGTTIN, 26 D background process attempted to read from control terminal
SIGTTOU, 27 D background process attempted to write from control terminal

The following signals are not listed in POSIX.1, but in SUSv2

Signal Value Processing
--------------------------------------------------------------------
SIGBUS, 7, and 10 C bus errors (wrong Memory Access)
The Pollable event defined by sigpoll a Sys V, which is synonymous with SIGIO
SIGPROF 27,27, 29 A Profiling timer
SIGSYS 12,-, 12 C invalid System Call (SVID)
SIGTRAP 5 C trace/breakpoint capture
SIGURG 4.2, 23, 21 B Socket emergency condition (BSD)
SIGVTALRM 26,26, 28 A Real-Time Alarm clock signal (4.2 BSD)
SIGXCPU 24, 24, and 30 C exceeds the set CPU time limit (4.2 BSD)
SIGXFSZ 4.2, 25, 31 C exceeds the set file size limit (BSD)

(For SIGSYS, SIGXCPU, SIGXFSZ, and SIGBUS in some machine architectures, the default action for Linux is A (terminate), and for SUSv2 is C (terminate and dump core )).

Below are some other signals

Signal Value Processing
----------------------------------------------------------------------
SIGIOT 6 c io capture command, synonymous with SIGABRT
SIGEMT 7,-, 7
SIGSTKFLT-, 16,-A coprocessor stack Error
SIGIO 4.2, 22 a I/O operation can now be performed (BSD)
SIGCLD-,-, 18 A is synonymous with SIGCHLD
SIGPWR 29,30, 19 A power supply fault (System V)
SIGINFO 29,-,-A is synonymous with SIGPWR
SIGLOST-,-,-A lost file lock
SIGWINCH 28, 28, 20 B window size change (4.3 BSD, Sun)
SIGUNUSED-, 31,-A unused signal (will be SIGSYS)

(Here,-indicates that the signal is not implemented. Three values indicate that the first value is always valid on Alpha and iSCSI, and the intermediate value corresponds to i386, ppc, and sh, the last value corresponds to mips. Signal 29 is SIGINFO/SIGPWR on Alpha and SIGLOST On iSCSI .)

The letter meanings in the action item are as follows:
The default action of A is to terminate the process.
The default action of B is to ignore this signal.
The default action of C is to terminate the process and perform a kernel image dumping (dump core)
D. The default action is to stop the process.
E signal cannot be captured
F signal cannot be ignored

The signals described above are supported by common systems. The following table describes the names, functions, and processing actions of various signals by default. The meaning of various default processing actions is: terminating a program means that the process exits; ignoring this signal means that the signal is discarded without processing; stopping a program means that the program is suspended, it can be re-executed after it enters the stopped state, usually in the debugging process (for example, ptrace System Call ); kernel image dumping refers to dumping the image of process data in the memory and part of the content of the process in the kernel structure to the file system in a certain format and exiting the execution, the advantage of doing so is to provide programmers with convenience, so that they can get the data value at the time the process was executed, allow them to determine the cause of the dump, and debug their program.

Note that the signal SIGKILL and SIGSTOP cannot be captured or ignored. SIGIOT and SIGABRT are signals. We can see that the same signal may have different values in different systems. Therefore, we recommend that you use a name defined for the signal instead of using the signal value directly.

Ii. Email System

The previous section describes the basic concepts of signals. In this section, we will introduce how the kernel implements the signal mechanism. That is, how the kernel sends signals to a process, how the process receives a signal, how the process controls its response to the signal, when the kernel processes the signal, and how it processes the signal received by the process. It also introduces the functions of setjmp and longjmp in signal.

1. Basic kernel Signal Processing Methods

The kernel sends Soft Interrupt signals to a process by setting the bit corresponding to the signal field in the process's progress table. What we need to add here is that if the signal is sent to a sleeping process, it depends on the priority of the process going to sleep. If the process goes to sleep, it will wake up the process; otherwise, only the corresponding bit of the signal field in the process is set, and the process is not wakened. This is important because the time when the process checks whether a signal is received is: when a process is about to return from the kernel state to the user State; or, when a process needs to enter or exit a proper low-scheduling priority sleep state.

The time when the kernel processes the signal received by a process is when a process returns the user State from the kernel state. Therefore, when a process runs in the kernel state, the soft interrupt signal does not take effect immediately and will not be processed until it returns to the user State. The process returns the user State only after processing the signal, and the process does not have the signal that has not been processed.

The kernel processes the Soft Interrupt signal received by a process in the context of the process. Therefore, the process must be in the running state. As mentioned above, there are three types of processing signals: The process exits after receiving the signal; the process ignores the signal; after receiving the signal, the process executes user settings to call the signal function using the system. When a process receives a signal that it ignores, the process discards the signal and continues running as if it did not receive the signal. If a process receives a signal to capture, the process executes user-defined functions when returning the user State from the kernel state. In addition, the method for Executing User-defined functions is clever. The kernel creates a new layer on the user stack, which sets the return address value to the address of the User-Defined processing function, in this way, the process returns to the user-defined function from the kernel to the top of the pop-up stack, and then the back of the function to the top of the stack to return the original entry to the kernel. The reason for this is that user-defined processing functions cannot and cannot be executed in the kernel state (if user-defined functions are run in the kernel state, the user can obtain any permissions ).

Pay special attention to the signal processing methods. First, in some systems, when a process processes the interrupt signal and returns the user State, the kernel clears the address of the processing routine for the signal set in the user area, that is, the next process changes the processing method for this signal to the default value, unless it is called again by the signal system before the next signal arrives. This may cause the process to exit after the signal is called. In BSD, the kernel does not clear this address. However, if this address is not cleared, the process may obtain a signal too quickly, resulting in stack overflow. In order to avoid the above situation. In the BSD system, the kernel simulates the hardware interrupt processing method, that is, when processing an interrupt, it prevents receiving new such interruptions.

Second, it should be noted that if the signal to be captured occurs when the process is being called by a system and the process is sleep at an interrupted priority, at this time, the signal causes the process to perform longjmp, jump out of the sleep state, return to the user State, and execute the signal processing routine. When a process is returned from a signal processing routine, it is like a system call, but an error code is returned, indicating that the system call has been interrupted. Note that the BSD kernel can automatically restart the system call.

Third, note that if a process is sleep at an interrupted priority, the process is awakened when it receives a signal to be ignored, but longjmp is not performed, generally, it is to continue sleep. However, the user does not feel that the process has been awakened, but does not have this signal.

The fourth thing to note: the processing method of the signal of the core sub-process termination (SIGCLD) is different from that of other signals. When a process detects that a sub-process is terminated, the process does not receive the signal by default. If the parent process executes the system to call wait, the process will wake up from the system call wait and return to the wait call, and execute a series of subsequent operations for the wait call (find dead sub-processes and release the sub-process entry ), then return from wait. The SIGCLD signal is used to wake up a sleep process that can be interrupted. If the process captures this signal, it will be transferred to the processing routine like normal signal processing. If the process ignores this signal, the system calls wait for different actions, because SIGCLD only serves to wake up a sleep process with a priority that can be interrupted, then the parent process that executes the wait call is awakened to continue the subsequent operations of the wait call, and then waits for other child processes.

If a process calls the signal system and sets the processing method of SIGCLD, and a sub-process is in zombie state, the kernel sends a SIGCLD signal to the process.

2. Functions of setjmp and longjmp

In the previous introduction to signal processing mechanisms, setjmp and longjmp were mentioned many times, but their functions and implementation methods were not carefully described. Here is a brief introduction.

When introducing the signal, we can see that the process requires the process to directly return from the original system call after checking that the signal is received, rather than waiting until the call is completed. This process suddenly changes its context, that is, the result of using setjmp and longjmp. Setjmp saves the saved context to the user zone and continues to execute it in the old context. This means that a process executes a system call. When it goes to sleep for resources or other reasons, the Kernel performs a setjmp for the process. If it is awakened by a signal during sleep, when a process cannot go to sleep, the kernel calls longjmp for the process. This operation is performed by the kernel to restore the context of the original setjmp call stored in the process user zone to the current context, in this way, the process can restore the status before waiting for resources, and the kernel returns 1 for setjmp, so that the process knows that the system call failed. This is what they do.

3. System Call of related Signals

The previous two sections have introduced most of the signal-related knowledge. In this section, let's take a look at these system calls. Specifically, the system calls signal to set the processing method of a signal, and the system calls kill to send a signal to a specified process. These two calls can form basic signal operations. The last two pause and alarm call are processes paused and timer implemented by signal, while alarm call is when the process timer is notified by signal. So here we will introduce these two calls.

1. signal System Call

The system calls signal to set the processing method of a signal. The call declaration format is as follows:
Void (* signal (int signum, void (* handler) (int );
Add the following header file to the process that uses this call:
# Include <signal. h>

The preceding Declaration format is complex. If you do not know how to use it, you can use the format defined in the following type (POSIX definition ):
Typedef void (* sighandler_t) (int );
Sighandler_t signal (int signum, sighandler_t handler );
However, this format has different type definitions in different systems. Therefore, you 'd better refer to the online manual to use this format.

In the call, the signum parameter indicates the signal to set the processing method. The second handler parameter is a processing function, or
SIG_IGN: Ignore the signal specified by the signum parameter.
SIG_DFL: the signal processing method specified by the recovery parameter signum is the default value.

The integer parameter passed to the signal processing routine is the signal value, so that a signal processing routine can process multiple signals. When the system calls signal, the return value is the processing routine of the previous signum signal or the error code SIG_ERR is returned. Here is a simple example:

# Include <signal. h>
# Include <unistd. h>
# Include <stdio. h>
Void sigroutine (int dunno) {/* signal processing routine, where dunno will get the signal value */
Switch (dunno ){
Case 1:
Printf ("Get a signal -- SIGHUP ");
Break;
Case 2:
Printf ("Get a signal -- SIGINT ");
Break;
Case 3:
Printf ("Get a signal -- SIGQUIT ");
Break;
}
Return;
}

Int main (){
Printf ("process id is % d", getpid ());
Signal (SIGHUP, sigroutine); // * set the processing method of the three signals below
Signal (SIGINT, sigroutine );
Signal (SIGQUIT, sigroutine );
For (;;);
}

The signal SIGINT is triggered by pressing Ctrl-C, and the signal SIGQUIT is triggered by pressing Ctrl. The execution result of this program is as follows:

Localhost :~ $./Sig_test
Process id is 463
Get a signal-SIGINT // the result obtained by pressing Ctrl-C.
Get a signal-SIGQUIT // press Ctrl-to Get the result
// Press Ctrl-z to place the process in the background
[1] + Stopped./sig_test
Localhost :~ $ Bg
[1] +./sig_test &
Localhost :~ $ Kill-HUP 463 // sends a SIGHUP signal to the Process
Localhost :~ $ Get a signal-SIGHUP
Kill-9 463 // send a SIGKILL signal to the process to terminate the process
Localhost :~ $

2. kill system call

The system calls kill to send a signal to the process. The call declaration format is as follows:
Int kill (pid_t pid, int sig );
Add the following header file to the process that uses this call:
# Include <sys/types. h>
# Include <signal. h>

This system call can be used to send any signal to any process or process group. If the pid parameter is positive, the call sends the signal sig to the process whose process number is pid. If the pid is equal to 0, the signal sig will be sent to all processes in the process group to which the current process belongs. If the pid is equal to-1, the signal sig will be sent to all processes except process 1 and itself. If the pid parameter is less than-1, the signal sig will be sent to all processes that belong to the Process Group-pid. If the sig parameter is 0, no signal is sent. When the call is successful, the returned value is 0. If an error is returned,-1 is returned, and the corresponding error code errno is set. Below are some error codes that may be returned:
EINVAL: the specified signal sig is invalid.
ESRCH: the process or process group specified by the pid parameter does not exist. Note: a process in the progress table may be a dead process that has not been withdrawn by wait but has been terminated.
EPERM: The process does not have the power to send the signal to the process specified to receive the signal. Because, when a process is allowed to send signals to the process pid, it must have root power, or the UID or EUID of the process that sends the call is the same as the UID of the specified process or the savedset-user-ID. If the pid parameter is less than-1, that is, the signal is sent to a group, the error indicates that a member process in the group cannot receive the signal.

3. pause system call

The system calls pause to wait for a signal. The Declaration format of this call is as follows:
Int pause (void );
Add the following header file to the process that uses this call:
# Include <unistd. h>

This call causes the calling process to sleep until it receives a signal. This call always returns-1 and sets the error code to EINTR (receiving a signal ). The following is a simple example:

# Include <unistd. h>
# Include <stdio. h>
# Include <signal. h>
Void sigroutine (int unused ){
Printf ("Catch a signal SIGINT ");
}

Int main (){
Signal (SIGINT, sigroutine );
Pause ();
Printf ("receive a signal ");
}

In this example, the program starts to execute, just like entering an endless loop, because the process is waiting for a signal. When we press Ctrl-C, the signal is captured, and causes the pause to exit the waiting state.

4. alarm and setitimer system call

The system calls the alarm function to set a timer. When the timer arrives, a signal is sent to the process. The Declaration format of this call is as follows:
Unsigned int alarm (unsigned int seconds );
Add the following header file to the process that uses this call:
# Include <unistd. h>

The system calls alarm to schedule the kernel to send a SIGALRM signal to the calling process after the specified seconds. If the specified seconds parameter is 0, the SIGALRM signal is no longer sent. The last setting will cancel the previous setting. The returned value is the time remaining between the last scheduled call and sending, or 0 is returned because there is no previous scheduled call.

Note: in use, alarm is only set to send a signal once. If you want to send a signal multiple times, you must use alarm for multiple calls.

For alarm, we will not give an example here. In the current system, many programs no longer use alarm calls, but use setitimer calls to set the timer. getitimer is used to get the timer status. The declaration formats of these two calls are as follows:
Int getitimer (int which, struct itimerval * value );
Int setitimer (int which, const struct itimerval * value, struct itimerval * ovalue );
Add the following header files to the processes that use these two calls:
# Include <sys/time. h>

The system provides three timers for processes. Each of them has its own timing domain. When any one of them arrives, a corresponding signal is sent to the process, and make the timer start again. The three timers are specified by the which parameter as follows:
TIMER_REAL: Timing by actual time. When the time arrives, the SIGALRM signal is sent to the process.
ITIMER_VIRTUAL: Timing is performed only when the process is executed. When the timer arrives, the SIGVTALRM signal is sent to the process.
ITIMER_PROF: timing when the process is executed and when the system executes the action for the process. It is a pair with the ITIMER_VIR-TUAL, which is often used to count the time spent by the process in the user and kernel states. When the timer arrives, the SIGPROF signal is sent to the process.

The parameter value in the timer is used to specify the timer time. Its structure is as follows:
Struct itimerval {
Struct timeval it_interval;/* Next value */
Struct timeval it_value;/* set this time */
};

The timeval structure in this structure is defined as follows:
Struct timeval {
Long TV _sec;/* seconds */
Long TV _usec;/* microseconds, 1 second = 1000000 microseconds */
};

In setitimer calls, if the parameter ovalue is not empty, the value set in the last call is retained. When the timer degrades it_value to 0, a signal is generated, and the it_value value is set to the it_interval value, and then the timing starts again. When it_value is set to 0, the timer stops, or when it expires and it_interval is set to 0. If the call is successful, 0 is returned. If an error is returned,-1 is returned, and the corresponding error code errno is set:
EFAULT: The parameter value or ovalue is an invalid pointer.
EINVAL: The which parameter is not one of ITIMER_REAL, ITIMER_VIRT, or ITIMER_PROF.

The following is a simple example of setitimer calling. In this example, a SIGALRM is sent every second and a SIGVTALRM signal is sent every 0.5 seconds:

# Include <signal. h>
# Include <unistd. h>
# Include <stdio. h>
# Include <sys/time. h>
Int sec;

Void sigroutine (int signo ){
Switch (signo ){
Case SIGALRM:
Printf ("Catch a signal -- SIGALRM ");
Break;
Case SIGVTALRM:
Printf ("Catch a signal -- SIGVTALRM ");
Break;
}
Return;
}

Int main (){
Struct itimerval value, ovalue, value2;
Sec = 5;

Printf ("process id is % d", getpid ());
Signal (SIGALRM, sigroutine );
Signal (SIGVTALRM, sigroutine );

Value. it_value. TV _sec = 1;
Value. it_value. TV _usec = 0;
Value. it_interval. TV _sec = 1;
Value. it_interval. TV _usec = 0;
Setitimer (ITIMER_REAL, & value, & ovalue );

Value2.it _ value. TV _sec = 0;
Value2.it _ value. TV _usec = 500000;
Value2.it _ interval. TV _sec = 0;
Value2.it _ interval. TV _usec = 500000;
Setitimer (ITIMER_VIRTUAL, & value2, & ovalue );

For (;;);
}

The Screen Copy in this example is as follows:

Localhost :~ $./Timer_test
Process id is 579
Catch a signal-SIGVTALRM
Catch a signal-SIGALRM
Catch a signal-SIGVTALRM
Catch a signal-SIGVTALRM
Catch a signal-SIGALRM
Catch a signal-GVTALRM

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.