UNIX advanced environment programming (13) signal, unix programming 13 Signal
The signal is Soft Interrupt.
Signals provide an asynchronous way to process events. For example, you can press the End Process key on the terminal to terminate a process in advance.
1. Concept of Signal
Each signal has a name whose names are headers with SIG. For example, every time a process calls the abort function, a SIGABRT signal is generated.
Each signal corresponds to a positive integer, which is defined in the header file <signal. h>.
If no signal corresponds to an integer 0, the kill function uses the signal number 0 to indicate a special case. Therefore, the signal number 0 is also called a null signal ).
The following situations generate a signal:
- When a user presses a specific key on the terminal, a signal is generated. For example, when you press the DELETE button (or Control-C), an interrupt signal (interrupt signal, SIGINIT) is generated, which terminates a running program.
- Hardware exceptions can generate signals. Hardware exceptions may occur, such as dividing by 0 and invalid memory reference. In this case, the hardware detects and notifies the kernel. Then, the kernel generates a signal to notify the corresponding running process. For example, when a process executes an invalid memory reference, the SIGSEGV signal is triggered.
- The kill function allows the current process to send arbitrary signals to other processes or process groups. Of course, this method has limitations: we must be the owner of the signal receiving process, or we must be a superuser ).
- The kill command is similar to the kill function. This command kills background processes by multiple users.
- Software exceptions can generate different signals based on different conditions. For example, when the data received in the network connection exceeds the boundary, the SIGURG signal is triggered.
For a process, the signal is generated randomly. Therefore, the process cannot simply determine whether the signal is generated based on the detection of whether a variable has changed. Instead, it should tell the kernel that "when this signal occurs, ".
We tell the kernel that what we do when a signal occurs is called a signal processing function. There are three functions available for signal processing functions:
- Ignore this signal. This behavior applies to most signals, except for two signals that cannot be ignored: SIGKILL and SIGSTOP. These two signals are neglected because they provide kernel and super users with a foolproof way to kill or pause processes (a surefire way ).
- Capture this signal. When a signal occurs, we tell the process to execute a program. In this program, we can do any operation to handle this situation. The SIGKILL and SIGSTOP signals cannot be captured.
- Execute the default signal processing program. Each signal has a default processing program, and most of the default processing programs terminate the process.
When some signals occur, the process is terminated, and a core file is generated. The core file records the memory condition when the process is terminated, which can help debugging and investigating the Process Termination status.
In several cases, core files are not generated:
- If the process sets the suid bit (chmod u + s file), and the current user is not the owner of the program file;
- If the process has set a guid (set-group-ID) and the current user is not the group owner of the program file;
- If the transfer does not have the write permission for the current working directory;
- If the core file already exists and the user does not have the write permission for the file;
- The core file is too large (restricted by the RLIMIT_CORE parameter)
2 signal function
Function Declaration
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
Returns: previous disposition of signal if OK, SIG_ERR on err.
Function declaration parsing:
Void (* signal (int signr, void (* handler) (int );
========================================================== ==========
Handler is a function pointer pointing to the void function whose parameter is single-parameter int.
Signal is a function pointer. This function pointer points to a parameter of the int type and a handler type. The return value is a pointer to a function of the int type and void type..
Summary:
This complex statement can be expressed in the following two simple forms:
The first type is as follows:
Typedef void (* handler_pt) (int );
Handler_pt signal1 (int signum, handler_pt ahandler );
The second type is as follows:
Typedef void handler_t (int );
Handler_t * signal2 (int signum, handler_t * ahandler );
------------------------------------------------------
The above two forms of results are equivalent, but there are also differences. The first form defines the function pointer type,
Sizeof (handler_pt) = 4 // borland c ++ 5.6.4 for win 32, windos xp 32 platform
The second form defines the function type. If sizeof (handler_t) is used for the function, the following message is displayed:
Sizeof may not be applied to a function
Parameter description:
- Signo: Signal name
- Func: three options: constant SIG_IGN, constant SIG_DFL, or the address of the signal processing function. If the value of func is SIG_IGN, the processing is ignored when the signal is generated (except for SIGKILL and SIGSTOP ). If the value of func is SIG_DFL, the default signal processing function is called.
In the above declaration parsing, we can see that using typedef can simplify the declaration of the signal function, and then the simplified declaration will be used for calls to the signal function:
typedef void Sigfunc(int);
Sigfunc *signal(int, Sigfunc *);
Example
The purpose of this example is to capture two user-defined signals and print relevant signal information.
Use the pause function to suspend the program and know the received signal.
Code
# Include "apue. h"
Staticvoid sig_usr (int);/* one handler for both signals */
Int
Main (void)
{
If (signal (SIGUSR1, sig_usr) = SIG_ERR)
Err_sys ("can't catch SIGUSR1 ");
If (signal (SIGUSR2, sig_usr) = SIG_ERR)
Err_sys ("can't catch SIGUSR2 ");
For (;;)
Pause ();
}
Staticvoid
Sig_usr (int signo)/* argument is signal number */
{
If (signo = SIGUSR1)
Printf ("received SIGUSR1 \ n ");
Else if (signo = SIGUSR2)
Printf ("received SIGUSR2 \ n ");
Else
Err_dump ("received signal % d \ n", signo );
}
Execution result:
During execution, we first let the program run in the background, and then call the kill command to send signals to the process.
Kill does not really kill the process, but sends signals. Therefore, kill does not accurately describe the role of the command.
When we call the kill 2081 command, the process is terminated because the signal is not processed in the signal processing function, and the default processing program of the signal is to terminate the process.
Program startup state
During program execution, all signals are in the default or ignored status.
If the program calls the exec system function, it will change the custom processing function of the signal to its default processing program, because the handler address in the original program is meaningless for the new program.
For example, when a background process is started in an interactive shell, the process of interrupting and exiting the process is set to ignore, when you type an interrupt command in the shell, only the foreground process is interrupted without affecting the background process.
This example also tells us a limitation of the signal function: we cannot confirm some signal processing actions of the current process unless we change them now. Next we will learn the sigaction function to confirm the processing actions of a signal without changing them.
Program Creation
When the fork function is called, the child process inherits the signal processing function of the parent process. Because the sub-process copies the memory of the parent process, the address of the signal processing function is also meaningful for the sub-process.
3. Unreliable Signals)
In earlier Unix systems, the signal was unreliable.
Unreliable means that the signal may be lost. That is, the signal occurs, but the process does not capture it.
We hope that the kernel can remember the signal. When we ready, let us know that the signal has occurred and let us process it.
In early systems, there was another problem with the implementation of the signal mechanism: When a signal occurs and a signal processing function is executed, the signal processing function is set to the default signal processing program. Therefore, the early Program Framework for signals is as follows:
The problem with this Code is that there is a time difference after the SIGINT signal occurs and before the signal processing function is reset to sig_int. Within this time difference, a sigint signal may occur again.
If the second SIGINT occurs before the signal processing function is reset, it will execute its default processing action, that is, terminate the process.
There is another problem in early implementation, that is, if a process does not want a signal to happen, it can only choose to ignore it, rather than close the signal.
One application scenario is: we do not want to be interrupted by signals, but we want to remember that they have happened. The code may be as follows:
Here, we assume that this signal only occurs once.
The purpose of the code is to wait for the signal to occur. Before the signal occurs, the process stops and waits.
The problem with the code is that there is a time difference and exceptions may occur. If the code execution sequence is as follows:
1 signal generation
2 while (sig_int_flag = 0)
3 sig_int_flag = 1
4 pause ()
At this time, the process suspends and waits for the signal to occur, but the signal has actually occurred. As a result, the signal is not captured.
4. Interruption of system calls
A feature of early Unix operating systems is that if a process is blocked in a "slow" system call, the process will receive a signal, resulting in the process being interrupted. An error is returned for this system call and errno is set to EINTR.
System calls are classified into two types: Slow system calls and other system calls. Slow system calls are those that may be permanently blocked. Slow system calls include:
- The Data Reading function may block callers. If the data is not in a specific format;
- Writing data functions may block callers. If data cannot be received immediately in a specific format.
- Open a file in a certain format
- Pause and wait Functions
- Specific ioctl operations
- Some inter-process communication functions
For system calls that can be interrupted, we need to process errno EINTR in the Code:
To avoid the need to explicitly handle the call that can interrupt the system, some call that can interrupt the system will be automatically restarted in case of blocking.
These automatically restarted and resumable system calls include: ioctl, read, readv, write, writev, wait, and waitepid.
If some applications do not want these system calls to restart automatically, you can set SA_RESTART separately for this system call.
5 reentrant Functions
The program's command execution sequence is disrupted by the occurrence of signals.
However, in the signal processing function, the execution of the original process cannot be known.
If the original process allocates or releases memory, or calls a function to modify the static variable and calls the function again in the signal processing function, unexpected results may occur.
A function that can be safely called in a signal processing function is also called a reentrant function or an asynchronous signal security function. In addition to reentrant guarantee, these functions also block signals that may cause inconsistent results.
If a function meets one or more of the following conditions, it indicates that the function cannot be reentrant:
- Use static data structure
- Call malloc or free
- Functions in the standard IO library, because most of the standard IO functions use the global data structure
6. SIGCLD Semantics
The two signals that are always confusing are SIGCLD and SIGCHLD.
SIGCLD comes from System V, while SIGCHLD comes from BSD and POSIX.1.
The meaning of bsd sigchld: When this signal occurs, it indicates that the sub-process status has changed. At this time, we need to call the wait function to confirm the status change.
In the System V System, the processing of the signal SIGCLD is described as follows:
7. Reliable Signal and Its Semantics
We first define several signal-related concepts:
- Signal Generation: if an event causes a signal, it is called a signal generation. This event may be a hardware exception, software condition, signal generated by the terminal, or signal transmitted by the kill function. When the signal is generated, the kernel needs to set a flag in the progress table.
- Signal delivery: when the signal processing function is executed, the signal is delivered.
- Signal suspension: the time between signal generation and delivery is called Signal suspension.
- Signal blocking: A process can choose not to receive a signal, which is called blocking the signal. If the processing of the blocked signal is a default processing program or captured processing, the signal will remain suspended, until the process unblocks the signal or changes the processing of the signal to ignore it. The system determines how to handle blocked signals during signal transmission, rather than when the signals are generated. The function sigpending is used to determine which signals are blocked and suspended by the process.
The reliability mechanism. Different standards have different solutions for abnormal situations:
- If a blocked signal is generated multiple times, the kernel simply transmits the signal once.
- If multiple signals are waiting to be transmitted, POSIX.1 does not focus on The signal transmission order, and The Rationale for POSIX.1 standard will ensure that signals related to The current state of The process are first transmitted.
- Each process has a signal mask to determine whether to shield a signal. each bit of the signal mask corresponds to a signal. If a signal is blocked, the corresponding signal is set to 1.
- The data structure sigset_t is defined to record the signal mask (signal mask)
References:
Advanced Programming in the UNIX Envinronment 3rd