Linux signal processing has been reading about the Linux signal number for the past two days. After reading the information, we should summarize it. of course, the following conclusions may be flawed. If you have any questions, you can learn them together. in fact, in real life, we all know what signals mean. In life, they are very simple and easy to understand. signals mean information. For example, when we fought in ancient times, when will the troops begin to fight, and when will they start to fight? When the Headquarters sends a "command", this command may be a horn, or a fireworks, and so on, we received a call. If a friend asks us to do something, we may do things right away after answering the call. These are the "horn", "Fireworks ", "telephone" is the "signal" we receive, and the subsequent action is what we do after receiving the signal. in fact, the same is true for computers. Many internal processes are running. If a process wants another process to do one thing, it can send a signal to notify another process, at this time, the signal communication between processes has played a certain role. Next we will look at the signal source, type, and process Signal. Www.2cto.com is actually a soft interrupt in the computer. It provides a method to handle asynchronous events and is also the only asynchronous communication method of the Process key. We know that Asynchronization means, there is no time rule at all. You (a process) can now handle what you want to do, and when a signal is detected, it will be processed again, that is, the occurrence of such a signal is random. there are two signal sources: hardware and software. there are many types of signals. in Linux, we can use the command kill-l on the terminal to view all the signals supported by the Linux system. As for the meaning of the signals, I will not repeat them here, if you are interested, you can read the relevant information to learn more. we can also <signal. h>. processes can process signals in three ways: capture signals, ignore signals, and process signals in the default mode. signal capturing and processing: in Linux, signal processing is mainly implemented by the signal and sigaction functions. 1. signal function: used to set the action of a process when it receives a signal. Enter man signal under shell to obtain the prototype of the function. # include <signal. h> typedef void (* sighandler_t) (int); sighandler_t signal (int signum, sighandler_t handler); signal sets the signal processing function based on the signal number specified by signum, when the specified signal arrives, it will be transferred to the parameter specified by handler for execution. If the handler parameter is not a function pointer, it must be a constant SIG_INT (ignore this signal) or SIG_DFL (signal processing by default ). if handler is a function pointer, the type of the function it points to is sighandler_t, that is, the function it points to has an int type parameter, and the return value type is void. if the function is successfully executed, the previous signal processing function pointer is returned. If an error occurs, the SIG_ERR (-1) is returned ). the following example shows how to use a signal function.: # Include <stdio. h> www.2cto.com # include <signal. h>/* signal processing function */void handler_sigint (int signo) {printf ("recv SIGINT \ n");} int main () {/* install the signal processing function */signal (SIGINT, handler_sigint); while (1); return;} when we run the program in the terminal, press Ctrl + C, the recv SIGINT will appear, and the recv SIGINT will continue to appear by pressing the button, but it will exit when we press Ctrl +, the press Ctrl + \ is equivalent to the signal SIGQUIT received by the process. The signal is used to terminate the process. If we ignore this signal, then the program will die forever, and it will not be returned, as shown in the following figure: # include <stdio. h> # include <signal. h> voi D handler_sigint (int signo) {printf ("recv SIGINT \ n");} www.2cto.com int main () {signal (SIGINT, handler_sigint); signal (SIGQUIT, SIG_INT ); // ignore this signal. At this time, Ctrl + \ no longer works. while (1); return;}: Why does the above exit? It is because the process does not process the signal SIGQUIT, so it follows the default method, that is, to end the process. next, let's look at the sigaction function: Similarly, man sigaction. You will see the prototype: # include <signal. h> int sigaction (int signum, const struct sigaction * act, struct sigaction * oldact) signum is the same as the above SIGKILL and SIGS Any signal other than TOP, while act is a struct pointer. If act is not a null pointer, set the signal processing function for signum. If oldact is not a null pointer, the old processing functions will be stored in oldact. next let's take a sigaction example: # include <stdio. h> # include <signal. h> int temp = 0; void handler_sigint (int signo) {printf ("recv SIGINT \ n"); sleep (5); temp + = 1; printf ("the value of temp is: % d \ n", temp); printf ("in handler_sigint, after sleep \ n");} int main () {struct sigaction act; act. sa_handler = handler_sigint; act. sa_flags = SA_NOMA SK; // This means that the signal can be transferred again before processing the second signal, which is equivalent to interrupting the nested sigaction (SIGINT, & act, NULL); while (1); return 0 ;} the running result of www.2cto.com is as follows: hfm @ hfm-Lenovo-KL6B-KL6C-Z475 :~ $ Gcc-o sigaction. chfm @ hfm-Lenovo-KL6B-KL6C-Z475 :~ $. /Sigaction ^ Crecv SIGINT ^ Crecv SIGINTthe value of temp is: 1in handler_sigint, after sleepthe value of temp is: 2in handler_sigint, after sleepthe value of temp is: 3in handler_sigint, after sleepthe value of temp is: 4in handler_sigint, after sleep
Note the meaning of Interrupt nesting I mentioned above. When we press Ctrl + c, the SIGINT signal is sent, printed, and then sleep for 5 seconds, but within these 5 seconds, you press Ctrl + c again, and then call the signal processing function handler_sigint nested from the sleep function. Five seconds later, the function prints the temp value, return to sleep and continue executing the second Ctrl + c that you just pressed. After the same operation, the value of temp is increased to 4, so the program returns to the function to continue the execution. Basically, the execution process is like this! The sending of signal processing functions is mainly completed by functions such as kill, faise, sigqueue, alarm, setitimer, and abort. run the man command to view the prototype of the kill function: # include <sys/types. h> # include <signal. h> int kill (pid_t pid, int sig); pid is the process number, while sig is the number of the sent signal, only root-authorized processes can send signals to any other process, while non-root-authorized processes can only send signals to processes of the same group or user. let's look at a simple example of simulating the kill command: kill. c # include <stdio. h> # include <signal. h> # include <stdlib. h> # include <sys/types. h> int main (int argc, char ** argv) {www.2cto.com int I, j; int signum = SIG TERM; pid_t pid; if (argc! = 2 & argc! = 4) {printf ("Usage :. /kill <-s signum> [pid] \ n "); exit (0) ;}for (I = 1; I <argc; I ++) {if (! Strcmp (argv [I], "-s") {signum = argv [I + 1]; break ;}} if (argc = 2) {pid = atoi (argv [1]);} else {for (j = 1; j <argc; j ++) {if (j! = I & j! = I + 1) {pid = atoi (argv [j]); break ;}}if (kill (pid, signum) <0) {perror ("kill "); exit (0);} return 0;} the signal SIGINT number is 2 in all Linux systems. the raise function is relatively simple and used to send signals to the process that calls it: Prototype: int faise (int sig); the sig parameter indicates the signal number to be sent, and 0 is returned successfully, A non-0 value is returned for failure. sigqueue function: it is a relatively new sending signal function. You can view the prototype using the man command. this function can not only send signals to processes, but also send data to processes. Its prototype is int sigqueue (pid_t pid, int sig, const union sigval value );
The following is an example: send_data_signo.c: transmits data using signals. This program sends data # include <stdio. h> # include <sys/types. h> # include <signal. h> # include <stdlib. h> int main (int argc, char ** argv) {union sigval value; int signum = SIGTERM; pid_t pid; int I; www.2cto.com value. sival_int = 0; if (argc! = 3 & argc! = 5 & argc! = 7) {printf (". /send_data_signo <-d data> <-s signum> [-p] [data] \ n "); exit (1) ;}/ * parse the signal number from the command line, PID and the data to be transmitted */for (I = 1; I <argc; I ++) {if (! Strcmp (argv [I], "-d") {value. sival_int = atoi (argv [I + 1]); continue;} if (! Strcmp (argv [I], "-s") {signum = atoi (argv [I + 1]); continue;} if (! Strcmp (argv [I], "-p") {pid = atoi (argv [I + 1]); continue ;}} /* use the sigqueue function to send signals */if (sigqueue (pid, signum, value) <0) {perror ("sigqueue"); exit (1 );} return 0;} in this example, the program receives data using signals # include <stdio. h> # include <signal. h> void handler_sigint (int signo, siginfo_t * siginfo, void * pvoid) {printf ("recv SIGINT, the data value is: % d \ n ", siginfo-> si_int);} int main () {struct sigaction act; act. sa_sigaction = handler_si Gint; act. sa_flags = SA_SIGINFO; // specify the three-parameter signal processing function sigaction (SIGINT, & act, NULL); while (1); www.2cto.com return 0;} For ease of writing, I named the process that sent the data B. c. The name of the receiving process is c. c run the above program results are as follows: hfm @ hfm-Lenovo-KL6B-KL6C-Z475 :~ $./C & [1] 4229hfm @ hfm-Lenovo-KL6B-KL6C-Z475 :~ $. /B-s 2-d 100-p 4229 recv SIGINT, the data value is: 100 alarm function: can be used to set the timer. When the timer times out, a SIGALRM signal is generated for the calling process, in shell, you can see the prototype: unsigned int alarm (unsigned int seconds). The parameter seconds indicates the set number of seconds. After seconds, the kernel sends a SIGALRM signal to the process that calls the function, if seconds is 0, no signal will be sent. The last time this function is called, the previous setting will be canceled. alarm is set to send a signal only once. If you want to send a signal multiple times, you must call alarm multiple times. if the alarm function has been called before, the remaining time of the previously set timer is returned. Otherwise, if no timer has been set before, 0 is returned. the following uses an example of simulated network ping to check the usage of the alarm function: # include <stdio. h> # include <Signal. h> # include <unistd. h> void send_ip () {printf ("send a icmp packet \ n");} void recv_ip () {while (1);} void handler_sigint (int signo) {send_ip (); alarm (2) ;}int main () {signal (SIGALRM, handler_sigint); raise (SIGALRM ); // trigger a SIGALRM signal to the process recv_ip (); return 0;} running results are as follows: hfm @ hfm-Lenovo-KL6B-KL6C-Z475 :~ $ Gcc-o m. chfm @ hfm-Lenovo-KL6B-KL6C-Z475 :~ $. /Msend a icmp packet www.2cto.com send a icmp packetsend a icmp packet ......... ..... we can see that every two seconds later, we will use the raise () function to start a SIGALRM signal to this process to implement the timed packet sending function of the ping program. at the same time, we can also imagine how the vro in the network sends the packet segment, which is also time-based. we can set the value in the alarm () function. in fact, there is also a function used to set the timer. It has more functions than alarm, namely the setitimer () function. Its prototype is as follows: int setitimer (int which, const struct itimerval * value, struct itimerval * ovalue); interested readers can take a look. the void abort (void) function is used to send a SIGABRT signal to the process to terminate the process. If the process sets SIGABRT to be blocked or ignored, abort () will overwrite this setting. this is what we have mastered. We will be able to conduct further research in the future. author hfm_honey