A signal (or soft interrupt) is a simulation of interrupts at the software level, which runs in "User space", and one process sends signals to another or several processes to achieve asynchronous communication. When the receiving process receives the signal, it can register the processing function to process these signals (optionally ignoring the signal or using the system default processing). I can see that through the kill-L "command to view the signals supported by the system, such as Sigkill it indicates the need to terminate a process, which has a system-specific signal value of 9. These values are defined in signal.h with a macro called _NSIG (typically 64) in signal.h that represents the maximum number of signals supported by the system, and Sigrtmax (_nsig-1) represents the maximum value of the signal, and the corresponding sigrtmin is not the minimum value representing the signal, which represents the minimum value of the reliable signal. According to the signal reliability, the signal can be divided into "reliable signal (real-time signal)" and "unreliable signal (non-real-time signal)", with sigrtmin as the limit, the value of less than sigrtmin signal is unreliable signal, which inherits from the early Unix system, Sigrtmin to Sigrtmax is a reliable signal. The unreliable signal has two points to note: First, it will reset the signal processing mode to the system default mode after executing the custom signal processing function (if you want to process the same signal multiple times, you will have to follow the signal processing function multiple times, but it seems like later Linux has improved this without reinstalling). Second, the unreliable signal does not support queuing, it is possible to have a signal loss situation. Assuming process a sends a signal to process B, a very simple signal flow is that process a calls a function to generate a signal, the signal is sent to process B, and process B processes the signal. Generation and transmission of signals: We use structural typedefstructSiginfo {//... some info of a signal} signifo_t; to represent information about a signal (such as the signal value, who sent it, etc.) with the structurestructSigqueue {structSigqueue *Next; siginfo_t info;}; To represent a queue of n siginfo_t structures. And then assume that there is a data structure: typedefstruct{unsignedLongsig[_nsig_words];} sigset_t, where _nsig_words represents a value that is typically 2. We know that long is 32 bits, then Sig[_nsig_words] is 64 bits, it can represent a collection of 64 bits, it is easy to map the elements in the collection to the _NSIG signal: If the bit is 1, the signal with the corresponding value is in the set. (In fact, because there is no signal number No. 0, so the signal value and bit value just stagger one bit) OK, how do we use these data structures to indicate which signals are sent to a process, very simply, if the process descriptor (PCB) has a sigset_t type of field, the corresponding position of the field 1 can be , and the details of these signals are more perfect if they can be saved in a field of the Sigqueue type. This is actually what the PCB does, except that it merges sigset_t and sigqueue into a structure called sigpending:structsigpending {structSigqueue *head, * *tail; sigset_t Signal;}; So the sigpending field of the PCB represents a signal that has been sent to the process but has not yet been processed (suspended). As we can see from here, the so-called "signal generation" is actually a process that requests the kernel to set the Sigpending field of another process to the corresponding value, and inserts the corresponding additional information into the Sigqueue queue. There is an interesting place to set up sigpending: We know that it is possible to use a bit in the sigset_t to indicate whether the corresponding signal is being sent to the process, which can simply mean "Yes (1) "or" None (0) ", if a signal is sent multiple times, it cannot be reflected in the sigset_t, but can be reflected through the Sigqueue queue, in fact, the corresponding unreliable signal (value is less than sigrtmin), when the sigpending set, if the kernel found signal _t the corresponding bit has been set to 1, then the kernel will discard the signal, which is why the signal is "unreliable", and the corresponding reliable signal, even if signal_t corresponding bit has been set 1, the relevant data of this signal (siginfo_t) Will still be packaged as a queue node and inserted into the queue. In addition, from a programming point of view, to send a signal, generally call the following functions:intKill (pid_t PID,intSIG); Send a signal to a process or process groupintRaiseintSIG); Signals to the calling process itselfintSigqueue (pid_t PID,intSigno,ConstUnion sigval value); Similar to kill, but with some additional information unsigned alarm (unsigned seconds); sends a SIGALRM signal (alarm signal) to the calling process after the specified timeintSetitimer (intWhich,Const structItimerval *value,structItimerval *ovalue); similar to the alarm SIGALRM signal, but support more detailed settings, more reference herevoidAbortvoid); sends a SIGABRT signal to the process to abort the process. When the receiving and processing process of the signal returns to the user state from the kernel state, the kernel checks to see if a signal is sent to the process, and if so, let the process handle the signal. The process can be handled in three ways for a signal:1, the signal is ignored in the display: where Sigkill and sigstop cannot be ignored, they must use the 2nd method below. 2, using the system default processing method: The default processing can be in such several ways: Abort, abort and dump, ignore; Stop (pause process, set to task_stopped state);Continue(Continue execution, corresponding to stop, set to task_running state)3, the call process registers the signal handler function for custom processing. When finished, the kernel changes the relevant values in the sigpending to indicate that the processing is complete (such as sigset_t the corresponding position 0, removing related elements from the sigqueue, etc.) as to how to register the signal processing function, Linux has the following two ways: TypeDefvoid(*sighandler_t) (int); sighandler_t Signal (intSignum, sighandler_t handler); Call the signal () function, which means that from now on I care for signals that signal value is signum, if the signal is sent to a stupid process, call handler to handle it. It is mainly used for non-reliable signals. For example, the following demo, to customize the processing SIGINT (press CTRL-c The signal is sent when the process is terminated) #include<stdio.h>#include<signal.h>#include<unistd.h>#defineSig2catch 2voidHandlerintSignum) {if(Signum = =Sig2catch) {printf ("wanna kill me with ctrl-c?! No way\n");}} intMain () {printf ("app start ... \ n"); Signal (Sig2catch, handler); while(1) {Sleep (1);} printf ("app end ... \ n"); return 0;} Run the program and try to use CTRL-C After the program is terminated, the SIGINT (value 2) signal is sent to the process, which terminates the program by default, but uses a custom handler that simply prints out a piece of text (you can use Ctrl-Z End) Another method of registration is:intSigaction (intSignumConst structSigaction *act,structSigaction *oldact); It is mainly used for reliable signals and can contain attachment information in the sigaction. For a detailed reference here.
Linux Process learning note-process signal Sigal