Linux programming signal (3): signal blocking and pending

Source: Internet
Author: User
Tags sigint signal

1. Representation of signals in the kernel

The processing action of the actually executed signal is called the delivery, the State between the signal generation and the delivery, and the pending ). A process can block a signal. When a blocked signal is generated, it remains in the pending state until the process unblocks the signal. Note that blocking and ignoring are different. As long as the signal is blocked, it will not be delivered. Ignoring is an optional action after delivery. The representation of signals in the kernel can be viewed as follows:


Each signal has two flags indicating blocking and pending, and a function pointer indicating processing actions. When the signal is generated, the kernel sets the pending flag of the signal in the process control block until the signal is delivered. In the example,
1. The sighup signal is neither blocked nor generated. When it is delivered, it performs the default processing action.

2. The SIGINT signal has been generated but is being blocked. Therefore, it cannot be delivered for the time being. Although the process is ignored, the signal cannot be ignored before the process is blocked, because the process still has the opportunity to change the process and then lift the blocking.

3. The sigquit signal has not been generated. Once the sigquit signal is generated, it will be blocked and its processing action is the User-Defined Function sighandler.

The pending and blocking signs can be stored using the same data type sigset_t. sigset_t is called a signal set. This type can indicate the "valid" or "invalid" status of each signal ,, in a blocked signal set, "valid" and "invalid" indicate whether the signal is blocked, in the pending signal set, "valid" and "invalid" indicate whether the signal is in the pending status. The blocked signal set is also called the signal shielding word (signal) of the current process.
Mask), the "blocking" here should be understood as blocking rather than ignoring.


Ii. Signal Set processing functions

The sigset_t type (64bit) uses one bit for each signal to indicate a "valid" or "invalid" status. As for how to store these bits in this type, it depends on the system implementation, users do not have to worry about it. Users can only call the following functions to operate the sigset_t variable, instead of interpreting its internal data, for example, printing the sigset_t variable directly with printf is meaningless.


# Include <signal. h>

Int sigemptyset (sigset_t * Set );

Int sigfillset (sigset_t * Set );

Int sigaddset (sigset_t * Set, int signo );

Int sigdelset (sigset_t * Set, int signo );

Int sigismember (const sigset_t * Set, int signo );


The sigemptyset function initializes the signal set pointed to by the set, so that the corresponding bits of all signals are cleared, indicating that the signal set does not contain any valid signal. The sigfillset function initializes the signal set pointed to by the set, so that the corresponding bit of all signals is set, indicating that the valid signal of the set includes all signals supported by the system. Note: Before using a variable of the sigset_t type, you must call sigemptyset or sigfillset for initialization so that the signal set is in a definite state. After the sigset_t variable is initialized, you can add or delete a valid signal in the signal set by calling sigaddset and sigdelset. All the four functions return 0 for success and-1 for error. Sigismember is a Boolean function used to determine whether a valid signal of a Signal Set contains a certain signal. if it contains a certain signal, 1 is returned. If it does not contain a certain signal, 0 is returned. If an error is returned,-1 is returned.

Iii. sigprocmask and sigpending Functions


1. Call the sigprocmask function to read or change the signal shielding characters of a process.


# Include <signal. h>

Int sigprocmask (INT how, const sigset_t * Set, sigset_t * oset );

Return Value: 0 if the request is successful, and-1 if the request fails.
If oset is a non-null pointer, the current signal shielding word of the read process is passed out through the oset parameter. If set is a non-null pointer, the signal shielding character of the process is changed. The parameter "how" indicates how to change it. If both oset and set are non-null pointers, back up the original signal shielding word to oset, and then change the signal shielding word according to the set and how parameters. Assuming that the current signal shielding word is mask, the following table describes the optional values of the how parameter.


2. sigpending reads the pending Signal Set of the current process and transmits it through the set parameter. If the call is successful, 0 is returned, and-1 is returned if an error occurs.

# Include <signal. h>

Int sigpending (sigset_t * Set );


Example program:

C ++ code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/*************************************** **********************************
> File name: Process _. c
> Author: Simba
> Mail: dameng34@163.com
> Created time: sat 23 Feb 2013 02:34:02 pm CST
**************************************** ********************************/
# Include <sys/types. h>
# Include <sys/STAT. h>
# Include <unistd. h>
# Include <fcntl. h>
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <string. h>
# Include <signal. h>

# Define err_exit (m )\
Do {\
Perror (m );\
Exit (exit_failure );\
} While (0)

Void handler (INT sig );
Void printsigset (sigset_t * Set)
{
Int I;
For (I = 1; I <nsig; I ++)
{
If (sigismember (set, I ))
Putchar ('1 ');
Else
Putchar ('0 ');
}
Printf ("\ n ");
}

Int flag = 0;

Int main (INT argc, char * argv [])
{
If (signal (SIGINT, Handler) = sig_err)
Err_exit ("signal error ");
If (signal (sigquit, Handler) = sig_err)
Err_exit ("signal error ");

Sigset_t pset; // 64bit
Sigset_t bset;
Sigemptyset (& bset );
Sigaddset (& bset, SIGINT );
Sigprocmask (sig_block, & bset, null );

For (;;)
{
Sigpending (& pset );
Printsigset (& pset );
Sleep (1 );
If (flag = 1)
Sigprocmask (sig_unblock, & bset, null );
}

Return 0;
}

Void handler (INT sig)
{
If (Sig = SIGINT)
Printf ("Recv a Sig = % d \ n", sig );
Else if (Sig = sigquit)
{
Printf ("Rev A Sig = % d \ n", sig );
Sigset_t uset;
Sigemptyset (& uset );
Sigaddset (& uset, SIGINT );
Sigprocmask (sig_unblock, & uset, null );
Flag = 1;
}

}

If you comment out the statements about the flag variable in the program, the output is as follows:

Simba @ Ubuntu :~ /Documents/code/linux_programming/apue/signal $./sigprocmask
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000

........................................ ...........................................

^ C0000000000000000000000000000000000000000000000000000000000000000000
0100000000000000000000000000000000000000000000000000000000000000

........................................ ........................................ ........................................ ...........................

^ \ Rev A Sig = 3
Recv a Sig = 2
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000

........................................ ........................................ ........................................ ....................

^ C0000000000000000000000000000000000000000000000000000000000000000000
0100000000000000000000000000000000000000000000000000000000000000

........................................ ........................................ ........................................ ...................


At the beginning of the program, add the SIGINT signal to the blocked Signal Set (that is, the signal shielding word). The endless loop keeps printing the pending Signal Set of the process. When we press Ctrl + C, because the signal is blocked, it is in the pending status, so the second output is 1 (SIGINT is the signal no. 2). Then, when we press Ctrl + \, we will send the sigquit signal, we removed the SIGINT blocking in handler, so the signal No. 2 was delivered and two lines of Recv statements were printed. At this time, the pending Signal Set became all 0. What is confusing is that we seem to have removed the blocking of SIGINT, but when we press Ctrl + C again
The signal is still in the pending status. Later, I wrote a test program and found that when blocking is removed, the pending bit is only cleared to 0, while the block bit is always 1, but I still feel puzzled, is a process that blocks a signal during its operation can only be delivered to it by clearing the pending bit each time, that is, the permanent cure? Later I thought it would be because the handler was removed? Therefore, a flag is set, that is, to add the four lines of code mentioned above, the previous output is the same, but after the blocking is removed again in the main function, press Ctrl + C to surprise the smooth delivery of Signal 2, as shown below:

^ Crecv a Sig = 2
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000

........................................ ........................................ ........................................ ...................

I checked the man manual of sigprocmask and did not find this point. But the actual test is like this: if a signal is blocked in the signal processing function, only the pending bit is cleared to 0, so that the signal is delivered once, but the block bit is not cleared to 0, that is, when the signal is generated again, it is blocked and in the pending status.

Now Ctrl + C and CTRL + \ cannot terminate the program. You can run another terminal kill-9 PID to kill the process.


Reference: apue and Linux C Programming one-stop learning

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.