在Linux服务端后台开发中,经常会用到信号处理函数:sigprocmask
和sigsuspend
。这篇文章主要通过一个综合实例演示如何使用sigprocmask函数屏蔽目标信号(信号掩码)以及sigsuspend函数挂起进程。
1 sigprocmask和sigsuspend函数的说明
关于sigprocmask
函数的说明:
头文件: #include <signal.h>
函数: int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能: 用于获取或者改变当前进程的信号掩码(当前进程屏蔽的信号集)。
返回值: 0成功,-1失败(具体原因由errno值表示)。
关于sigsuspend
函数的说明:
头文件: #include <signal.h>
函数: int sigsuspend(const sigset_t *mask);
功能: 阻塞当前进程(TASK_INTERRUPTIBLE可中断状态),等待mask信号集(信号掩码)之外的任何信号的到来。
在收到pendmask之外)信号后,先调用该信号的处理函数,然后把信号集mask还原为原来的信号集,接着从sigsuspend调用处返回(进程恢复执行)。
返回值: 该系统调用始终返回-1,并将errno设置为EINTR。
2 完整的程序实例
在CentOS服务器中使用编译并执行下面这段程序,效果如上图所示。
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 | /**
* @FileName sigprocmask_sigsuspend.c
* @Describe A simple example for using sigprocmask and sigsuspend functions in linux.
* @Author vfhky 2016-02-29 11:21 https://typecodes.com/cseries/sigprocmasksigsuspendapp.html
* @Compile gcc sigprocmask_sigsuspend.c -o sigprocmask_sigsuspend
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
//Signal handle function.
void sig_handler( int signal )
{
printf( "Receive signal=[%d].\n", signal );
return;
}
int main( int argc, char *argv[] )
{
printf( "getpid=[%d].\n", getpid() );
int i = 0;
//Register a signal.
struct sigaction new_act;
sigemptyset( &new_act.sa_mask );
new_act.sa_handler = sig_handler;
new_act.sa_flags = 0;
sigaction( SIGUSR1, &new_act, 0 );
sigaction( SIGUSR2, &new_act, 0 );
sigaction( SIGINT, &new_act, 0 );
//Add SIGINT, SIGUSR1/SIGUSR2 signals to the signal-set of new_set.
sigset_t new_set, old_set;
sigemptyset( &new_set );
sigaddset( &new_set, SIGINT ); //2
sigaddset( &new_set, SIGUSR1 ); //10
//sigaddset( &new_set, SIGUSR2 ); //12
/**
* Repalce the old mask set with the new mask set.Thus the process will block the signal of SIGINT and SIGUSR1,
* but it will excute the function of sig_handler when the signal such as SIGUSR2 other than SIGINT, SIGUSR1 arrives.
*/
sigprocmask( SIG_SETMASK, &new_set, &old_set );
//Add SIGUSR1 and SIGUSR2 signals to the signal-set of pendmask.
sigset_t pendmask;
sigemptyset( &pendmask );
sigaddset( &pendmask, SIGUSR1 ); //10
sigaddset( &pendmask, SIGUSR2 ); //12
//Replaces the signal mask of the process with pendmask temporarily and suspends the process until delivery of a signal whose action is to invoke a signal handler or to terminate a process.
i = sigsuspend( &pendmask );
printf( "Sigsuspend returned with value[%d].\n", i );
if( errno == EINTR )
{
printf( "[%d]Interrupted by a signal.\n", errno );
}
while(1)
{
printf( "--while.\n" );
sleep(3);
}
return 0;
}
|
3 发送SIGUSR1和SIGUSR2信号
如下图所示,使用kill
命令向进程(PID:7154)发送SIGUSR1
和SIGUSR2
信号。
由于sigsuspend
函数把信号SIGUSR1
和SIGUSR2
加入到信号掩码pendmask
中,所以这两个信号的到来对当前进程没有任何影响。
4 发送SIGINT信号
使用命令kill -SIGINT 7154
向当前进程(PID:7154)发送SIGINT
信号。由于该信号不在信号掩码pendmask
中,所以先调用SIGINT
信号的处理函数sig_handler,然后把现在的信号集pendmask
还原为原来的new_set
信号集。
这时,由于之前由于信号掩码pendmask
被屏蔽的未决信号信号SIGUSR1
和SIGUSR2
由内核重新传递,所以进程会执行SIGUSR2
信号的处理函数(SIGUSR1信号被信号集new_set所屏蔽,因此不会执行)。接着进程从sigsuspend调用处返回,恢复执行(进入while循环)。
如果继续发送SIGINT
信号,因为被加入到了当前信号掩码new_set
中,所以也会被屏蔽(对进程无影响)。最后可以通过命令kill -SIGKILL 7154
将整个进程关闭。
Comments »