一个sigprocmask和sigsuspend函数的综合应用

在Linux服务端后台开发中,经常会用到信号处理函数:sigprocmasksigsuspend。这篇文章主要通过一个综合实例演示如何使用sigprocmask函数屏蔽目标信号(信号掩码)以及sigsuspend函数挂起进程。

Linux中编译执行sigprocmask_sigsuspend程序

一、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。

二、完整的程序实例

在CentOS服务器中使用编译并执行下面这段程序,效果如上图所示。

main.c
/**
 * @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;
}

三、发送SIGUSR1和SIGUSR2信号

如下图所示,使用kill命令向进程(PID:7154)发送SIGUSR1SIGUSR2信号。

发送SIGUSR1和SIGUSR2信号

由于sigsuspend函数把信号SIGUSR1SIGUSR2加入到信号掩码pendmask中,所以这两个信号的到来对当前进程没有任何影响。

四、发送SIGINT信号

使用命令kill -SIGINT 7154向当前进程(PID:7154)发送SIGINT信号。由于该信号不在信号掩码pendmask中,所以先调用SIGINT信号的处理函数sig_handler,然后把现在的信号集pendmask还原为原来的new_set信号集。

这时,由于之前由于信号掩码pendmask被屏蔽的未决信号信号SIGUSR1SIGUSR2由内核重新传递,所以进程会执行SIGUSR2信号的处理函数(SIGUSR1信号被信号集new_set所屏蔽,因此不会执行)。接着进程从sigsuspend调用处返回,恢复执行(进入while循环)。

执行SIGINT和SIGUSR2信号处理函数

如果继续发送SIGINT信号,因为被加入到了当前信号掩码new_set中,所以也会被屏蔽(对进程无影响)。最后可以通过命令kill -SIGKILL 7154将整个进程关闭。

继续发送SIGINT和SIGKILL信号

评论

评论加载中…