First, the signal life cycle
Execution complete from signal to signal processing function
For a complete signal life cycle (from signal sent to the corresponding processing function completed), can be divided into three important stages, these three stages are characterized by four important events: The signal is born, the signal is registered in the process, the signal is logged in the process, the signal processing function is completed. The time interval of two adjacent events constitutes a phase of the signal life cycle.
The following illustrates the practical significance of the four events:
- The signal "born". The birth of a signal is the occurrence of an event that triggers a signal, such as a hardware exception detected, a timer timeout, and a call to signal sending function kill () or Sigqueue ().
- The
- signal is "registered" in the target process, and the TASK_STRUCT structure of the process has data members about the outstanding signals in the process:
struct sigpending pending:struct Sigpending{struct sigqueue *head, **tail;sigset_t Signal;};
The third member is all the outstanding signal sets in the process, the first and second members point to the end of a structure chain of sigqueue type (called the "pending signal information chain"), each sigqueue structure in the information chain depicts the information carried by a particular signal, and point to the next Sigqueue structure: struct sigqueue{struct sigqueue *next;siginfo_t info;}
The
signal in process registration refers to the signal value added to the process's pending signal set (the second member of the sigpending structure sigset_t signal), and the information carried by the signal is retained in a sigqueue structure of the pending signal information chain. As long as the signal is in the pending signal set of the process, it indicates that the process is aware of the presence of these signals but has not yet been processed, or that the signal is blocked by the process. Note:
When a real-time signal is sent to a process, regardless of whether the signal is registered in the process, it will be re-registered once, so the signal is not lost, so the real-time signal is also called "reliable signal". This means that the same real-time signal can occupy multiple sigqueue structures in the pending signal information chain of the same process (the process receives a real-time signal, assigns it a structure to register the signal information, and adds the structure to the left of the pending signal chain, i.e. all real-time signals that are born are registered in the target process) ;
When a non-real-time signal is sent to a process, if the signal is already registered in the process, the signal is discarded, causing the signal to be lost. Therefore, the non-real-time signal is also called "unreliable signal". This means that the same non-real-time signal in the process of the pending signal information chain, at most occupy a sigqueue structure (a non-real-time signal is born, (1), if the same signal is found in the target structure is registered, then no longer registered, for the process, the equivalent of not know this signal occurs, signal loss ; (2), if there is no same signal in the pending signal of the process, register itself in the process).
- The signal is logged off in the process. During the execution of the target process, it detects if there is a signal waiting to be processed (such checks are made every time the system space is returned to the user space). If there is a pending signal waiting to be processed and the signal is not blocked by the process, the process will remove the structure that the signal occupies in the pending signal chain before running the corresponding signal processing function. Whether the signal is removed from the process pending signal set is different for real-time and non-real-time signals. For the non-real-time signal, because in the outstanding signal information chain to occupy a maximum of one sigqueue structure, so that the structure is released, the signal should be removed in the process pending signal set (signal cancellation), and for real-time signal, may occupy the outstanding signal information chain in a plurality of sigqueue structure, Therefore it should be treated differently for the number of occupied sigqueue structures: If only one sigqueue structure is used (the process only receives the signal once), then the signal should be removed in the process's pending signal set (signal logoff is complete). Otherwise, the signal should not be removed from the pending signal set in the process (signal logoff is complete).
The process will first log out of the process before executing the signal corresponding handler function.
- Signal life is terminated. After the process logoff signal, immediately execute the corresponding signal processing function, after execution, the signal of this send to the impact of the process completely ended.
Note:
1) Whether the signal is registered or not, regardless of the function that sends the signal (such as Kill () or Sigqueue (), and the signal installation function (signal () and sigaction ()), only related to the signal value (signal value less than sigrtmin signal is only registered once, Signal value between Sigrtmin and Sigrtmax, as long as the process is received to be registered).
2) When the signal is written off to the corresponding signal processing function completion period, if the process receives the same signal multiple times, for the real-time signal, each time will be registered in the process, and for the non-real-time signal, no matter how many times the signal received, will be considered to receive only one signal, only in the process register once.
Back to top of page
Second, signal programming considerations
- Prevent missing signals from being lost. If you understand the signal life cycle mentioned in eight, it is easy to know if the signal will be lost or lost.
- Program Portability
The POSIX signal functions should be used as much as possible, and POSIX signal functions are divided into two main categories:
- POSIX 1003.1 signal functions: Kill (), Sigaction (), Sigaddset (), Sigdelset (), Sigemptyset (), Sigfillset (), Sigismember (), sigpending (), Sigprocmask (), Sigsuspend ().
- POSIX 1003.1b signal function. POSIX 1003.1b extends POSIX 1003.1 in the real-time aspect of the signal, including the following three functions: Sigqueue (), sigtimedwait (), Sigwaitinfo (). Among them, sigqueue mainly for signal transmission, while sigtimedwait and Sigwaitinfo () are mainly used to replace the sigsuspend () function, followed by a corresponding example.
#include <signal.h>int sigwaitinfo (sigset_t *set, siginfo_t *info).
This function, like sigsuspend (), blocks a process until a particular signal occurs, but does not execute a signal processing function when the signal arrives, but instead returns the signal value. Therefore, in order to avoid the execution of the corresponding signal processing function, it must be called before the function, so that the process to screen out the signal set point, so the typical code called the function is: sigset_t newmask;int Rcvd_sig; siginfo_t Info;sigemptyset (&newmask); Sigaddset (&newmask, sigrtmin); Sigprocmask (SIG_BLOCK, &newmask, NULL); Rcvd_sig = Sigwaitinfo (&newmask, &info) if (Rcvd_sig = =-1) {:}
The
call returns a signal value successfully, otherwise returns-1. Sigtimedwait () functions Similarly, but increases the time that a process waits.
- the stability of the program.
To enhance the stability of the program, the Reentrant function should be used in the signal processing function.A reentrant (reentrant) function should be used in a signal handler (note: The so-called reentrant function refers to a process that can be called by multiple tasks, and the task does not have to worry about data errors when it is called). Since the process receives the signal, it jumps to the signal handler to proceed. If a non-reentrant function is used in a signal-processing function, the signal-processing function may modify data that should not be modified in the original process, so that the process may have unpredictable consequences when it returns to execution from the signal handler function. The non-reentrant function is considered an unsafe function in the signal processing function.
Most of the functions that meet the following conditions are non-reentrant: (1) using static data structures such as GetLogin (), Gmtime (), Getgrgid (), Getgrnam (), Getpwuid (), Getpwnam (), and so on (2) when the function is implemented, The malloc () or free () function was called, and (3) The standard I/O function was used when implemented. The Open group sees the following functions as Reentrant:
_exit (), Access (), Alarm (), Cfgetispeed (), Cfgetospeed (), Cfsetispeed (), Cfsetospeed (), ChDir (), chmod (), Chown (), Close (), creat (), DUP (), dup2 (), Execle (), Execve (), Fcntl (), fork (), fpathconf (), Fstat (), Fsync (), Getegid (), Geteuid (), Getgid (), GetGroups (), Getpgrp (), Getpid (), Getppid (), Getuid (), Kill (), link (), Lseek (), mkdir (), Mkfifo (), open (), Pathconf (), pause (), pipe (), raise (), read (), rename (), RmDir (), Setgid (), Setpgid (), Setsid (), setuid (), Sigaction (), Sigaddset (), Sigdelset (), Sigemptyset (), Sigfillset (), sigismember (), signal (), sigpending (), Sigprocmask (), Sigsuspend (), Sleep (), stat (), sysconf (), Tcdrain (), Tcflow (), Tcflush (), tcgetattr (), Tcgetpgrp (), Tcsendbreak (), Tcsetattr (), Tcsetpgrp (), Time (), Times (), Umask (), uname (), unlink (), Utime (), Wait (), Waitpid (), write ().
Even if the signal processing function uses "safe functions", it is also important to note that when entering a processing function, the value of errno is first saved, and the original value is restored at the end. Because, during signal processing, the errno value may be changed at any time. In addition, longjmp () and siglongjmp () are not listed as reentrant functions because there is no guarantee that other calls to the next two functions are safe.
Back to top of page
Three, in layman: Signal Application Example
The signal application under Linux is not as scary as it is imagined, and there are only three things programmers have to do:
- Installation Signal (Sigaction () recommended);
- Implement three-parameter signal processing function, handler (int signal,struct siginfo *info, void *);
- To send a signal, it is recommended to use Sigqueue ().
In fact, for some signals, it is sufficient to install the signal (the signal processing method is either default or ignored). The other things you might want to do are just a few operations related to the signal set.
Example one: signal sending and processing
Implement a Signal receiver program sigreceive (where the signal is installed by sigaction ()).
#include <signal.h> #include <sys/types.h> #include <unistd.h>void new_op (int,siginfo_t*,void*); int main (int argc,char**argv) {struct sigaction act;int sig;sig=atoi (argv[1]); Sigemptyset (&act.sa_mask); Act.sa_ Flags=sa_siginfo;act.sa_sigaction=new_op;if (Sigaction (Sig,&act,null) < 0) {printf ("Install Sigal error\n");} while (1) {sleep (2);p rintf ("Wait for the Signal\n");}} void New_op (int signum,siginfo_t *info,void *myact) {printf ("Receive signal%d", signum); sleep (5);}
Description, command-line parameters for the signal value, the background runs sigreceive Signo &, the ID of the process can be obtained, assuming that the PID, and then run on another terminal kill-s signo PID verification signal send and receive and processing. At the same time, the signal queuing problem can be verified.
Note: You can use Sigqueue to implement a command line signaling program Sigqueuesend, see Appendix 1.
Example two: Signal transmission additional information
There are two main examples:
- Sends a signal to the process itself and passes the pointer parameters;
#include <signal.h> #include <sys/types.h> #include <unistd.h>void new_op (int,siginfo_t*,void*); int main (int argc,char**argv) {struct sigaction act;union sigval mysigval;int i;int sig;pid_t Pid;char data[10];memset ( Data,0,sizeof (data)); for (I=0;i < 5;i++) data[i]= ' 2 '; Mysigval.sival_ptr=data;sig=atoi (argv[1]);p id=getpid (); Sigemptyset (&act.sa_mask); act.sa_sigaction=new_op;//three-parameter signal processing function act.sa_flags=sa_siginfo;//Information transfer switch if (Sigaction ( Sig,&act,null) < 0) {printf ("Install Sigal error\n");} while (1) {sleep (2);p rintf ("Wait for the signal\n"); Sigqueue (pid,sig,mysigval);//Send a signal to the process and pass additional information}}void new_op (int signum,siginfo_t *info,void *myact)//The implementation of the three-parameter signal processing function {int i;for (i=0;i<10;i++) {printf ("%c\n", (* (char*) ((*info). Si_ PTR)) (+i)));} printf ("handle signal%d over;", Signum);}
In this example, the signal implements the transfer of additional information, and how the signal is processed depends on the specific application.
- 2. Transfer integer parameters between different processes: the signal sending and receiving in 1 is placed in two programs, and the integer parameters are passed in the sending process.
Signal Receiving Program:#include <signal.h> #include <sys/types.h> #include <unistd.h>void new_op (int,siginfo_t*,void*); int main (int argc,char**argv) {struct sigaction act;int sig;pid_t pid;pid=getpid (); Sig=atoi (argv[1]); Sigemptyset ( &act.sa_mask); Act.sa_sigaction=new_op;act.sa_flags=sa_siginfo;if (Sigaction (Sig,&act,NULL) <0) {printf ("Install Sigal error\n");} while (1) {sleep (2);p rintf ("Wait for the Signal\n");}} void New_op (int signum,siginfo_t *info,void *myact) {printf ("The int value is%d \ n", info->si_int);}
Signal Sender: Command line The second parameter is the signal value, and the third parameter is the receive process ID.
#include <signal.h> #include <sys/time.h> #include <unistd.h> #include <sys/types.h>main (int ARGC,CHAR**ARGV) {pid_t pid;int signum;union sigval mysigval;signum=atoi (argv[1]);p id= (pid_t) atoi (argv[2]); mysigval.sival_int=8;//does not represent a specific meaning and is used only to illustrate the problem if (Sigqueue (pid,signum,mysigval) ==-1) printf ("Send error\n"); Sleep (2);}
Note: Example 2 of two examples of the focus is to use the signal to transmit information, the current on Linux through the signal transmission of information is very small, but there are some Unix, but the transfer is basically about passing an integer, passing pointers I have not seen. I have not implemented pointer passing between different processes (actually more meaningful), perhaps there is a problem with the implementation method, please email me.
Example three: signal blocking and Signal set operation
#include "signal.h" #include "unistd.h" static void My_op (int); main () {sigset_t new_mask,old_ Mask,pending_mask;struct sigaction Act;sigemptyset (&act.sa_mask); Act.sa_flags=sa_siginfo;act.sa_sigaction= ( void*) my_op;if (Sigaction (sigrtmin+10,&act,null)) printf ("Install signal sigrtmin+10 error\n"); Sigemptyset ( &new_mask); Sigaddset (&new_mask,sigrtmin+10); if (Sigprocmask (Sig_block, &new_mask,&old_mask)) printf ("Block signal sigrtmin+10 error\n"), Sleep;p rintf ("Now begin to get pending mask and unblock sigrtmin+10\n"); if (Sigpending (&pending_mask) <0) printf ("Get Pending Mask error\n"); if (Sigismember (&pending_mask,sigrtmin+ ) printf ("Signal sigrtmin+10 is pending\n"), if (Sigprocmask (sig_setmask,&old_mask,null) <0) printf ("Unblock Signal error\n ");p rintf (" Signal unblocked\n "); sleep (10);} static void My_op (int signum) {printf ("receive signal%d \ n", Signum);}
Compile the program and run it in the background. In the other terminal to send a signal to the process (running Kill-s pid,sigrtmin+10 is 42), view the results can be seen several key functions of the operating mechanism, the signal set related operation is relatively simple.
Note: in the above few instances, the printf () function is used, but as a diagnostic tool, the PRINGF () function is not reentrant and should not be used in signal processing functions.
Back to top of page
Conclusion:
The systematic analysis and summary of the Linux signal mechanism benefit me greatly! Thank Wangxiaolo and other netizens for their support!
Comments and suggestions are greatly welcome!
Back to top of page
Appendix 1:
Command line signaling program implemented with Sigqueue Sigqueuesend, command line the second parameter is the signal value sent, the third parameter is the process ID that receives the signal, can be used with instance one:
#include <signal.h> #include <sys/types.h> #include <unistd.h>int main (int argc,char**argv) {pid_t Pid;int Sig;sig=atoi (argv[1]);p id=atoi (argv[2]); Sigqueue (pid,sig,null); sleep (2);}
Linux Signal Processing Four