码迷,mamicode.com
首页 > 其他好文 > 详细

《UNIX环境高级编程》读书笔记之信号(2)

时间:2014-10-11 20:10:26      阅读:350      评论:0      收藏:0      [点我收藏+]

标签:unix环境高级编程

1.函数sigaction

sigaction函数的功能是检查或修改与指定信号相关联的处理动作。其函数原型如下:

#inlcude <signal.h>

int sigaction(int signo,const struct sigaction * restrict act,struct sigaction * restrict act);

其中参数signo是要检测或修改其具体动作的信号编号。若act指针非空,则要修改其动作。如果oact指针非空,则系统经由oact指针返回该信号的上一个动作。结构体sigaction的结构如下:

bubuko.com,布布扣

一旦对给定的信号设置了一个动作,那么在调用signation显式的改变它之前,该设置就一直有效。

act结构的sa_flags字段指定对信号进行处理的各个选项。下图详细列出了这些选项的意义。

bubuko.com,布布扣

sigaction结构的sa_sigaction字段是一个替代的信号处理程序。当sa_flags设置了SA_SIGINFO标志时,使用该信号处理程序。通常,信号处理函数的形式是这样的:void handler(int signo)。但如果设置了SA_SIGINFO标志,则信号处理函数的原型是这样的:void handler(int signo,siginfo_t *info,void *context)。siginfo_t结构包含了信号产生原因的有关信息。该结构的样式如下所示:

bubuko.com,布布扣

context参数是无类型指针,它可被强制类型转换为ucontext_t结构类型,该结构标识信号传递时的上下文信息。


2.函数sigsetjmp和siglongjmp

在信号处理程序中进行非局部转移时使用这两个函数。

#include <setjmp.h>

int sigsetjmp(sigjmp_buf env,int savemask);//若直接调用,返回0。若从siglongjmp调用返回,则返回非0。

void siglongjmp(sigjmp_buf env,int val);

在调用sigsetmask时,如果savemask值为1,则将进程当前的屏蔽字保存在env中。调用siglongjmp时,如果带非0savemask的sigsetjmp调用已经将进程的屏蔽字保存在env中了,则siglongjmp从中恢复保存的信号屏蔽字。

例:

#include "apue.h"
#include <setjmp.h>
#include <time.h>

static void sig_usr1(int);
static void sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;

void pr_mask(const char *str)//打印当前被阻塞的信号
{
        sigset_t sigset;
        int errno_save;

        errno_save = errno; /* we can be called by signal handlers */
        if (sigprocmask(0, NULL, &sigset) < 0)
                perror("sigprocmask error");

        printf("mask: %s", str);
        if (sigismember(&sigset, SIGINT)) printf("SIGINT ");
        if (sigismember(&sigset, SIGQUIT)) printf("SIGQUIT ");
        if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
        if (sigismember(&sigset, SIGUSR2)) printf("SIGUSR2 ");
        if (sigismember(&sigset, SIGALRM)) printf("SIGALRM ");

        /* remaining signals can go here */

        printf("\n");
        errno = errno_save;
}

Sigfunc * signal(int signo,Sigfunc * func)
{
	struct sigaction act,oact;
	act.sa_handler = func;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	if(signo == SIGALRM) {
	#ifdef SA_INTERRUPT
		act.sa_flags |= SA_INTERRUPT;
	#endif
	} else {
		act.sa_flags |= SA_RESTART;	
	}
	if(sigaction(signo,&act,&oact) < 0)
		return (SIG_ERR);
	return (oact.sa_handler);
}

int main(void)
{
	if(signal(SIGUSR1,sig_usr1) == SIG_ERR)
		err_sys("signal(SIGUSR1) error");

	if(signal(SIGALRM,sig_alrm) == SIG_ERR)
                err_sys("signal(SIGALRM) error");

	pr_mask("starting main:");
	
	if(sigsetjmp(jmpbuf,1)) {
		pr_mask("ending main:");
		exit(0);
	}
	canjump = 1;
	for(;;)
		pause();	
}

static void sig_usr1(int signo)
{
	time_t starttime;
	
	if(canjump == 0)
		return;
	
	pr_mask("starting sig_usr1:");
	
	alarm(3);
	starttime = time(NULL);
	for(;;)
		if(time(NULL) > starttime+5)
			break;
	pr_mask("finishing sig_usr1:");
	canjump = 0;
	siglongjmp(jmpbuf,1);
}

static void sig_alrm(int signo)
{
	pr_mask("in sig_alrm:");
}

3.函数sigsuspend

#include <signal.h>

int sigsuspend(const sigset_t * sigmask);

进程的信号屏蔽字设置由sigmask指定。在捕捉到一个信号前,该进程被挂起。如果捕捉到一个信号,则sigsuspend返回,并且该进程的新高屏蔽字设置为以前的值。

例:

#include "apue.h"

static void sig_int(int);

void pr_mask(const char *str)//打印当前被阻塞的信号
{
        sigset_t sigset;
        int errno_save;

        errno_save = errno; /* we can be called by signal handlers */
        if (sigprocmask(0, NULL, &sigset) < 0)
                perror("sigprocmask error");

        printf("mask: %s", str);
        if (sigismember(&sigset, SIGINT)) printf("SIGINT ");
        if (sigismember(&sigset, SIGQUIT)) printf("SIGQUIT ");
        if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
        if (sigismember(&sigset, SIGUSR2)) printf("SIGUSR2 ");
        if (sigismember(&sigset, SIGALRM)) printf("SIGALRM ");

        /* remaining signals can go here */

        printf("\n");
        errno = errno_save;
}

Sigfunc * signal(int signo,Sigfunc * func)
{
	struct sigaction act,oact;
	act.sa_handler = func;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	if(signo == SIGALRM) {
	#ifdef SA_INTERRUPT
		act.sa_flags |= SA_INTERRUPT;
	#endif
	} else {
		act.sa_flags |= SA_RESTART;	
	}
	if(sigaction(signo,&act,&oact) < 0)
		return (SIG_ERR);
	return (oact.sa_handler);
}

int main(void)
{
	sigset_t newmask,oldmask,waitmask;
	
	pr_mask("program start:");
	
	if(signal(SIGINT,sig_int) == SIG_ERR)
		err_sys("signal(SIGINT) error");
	sigemptyset(&waitmask);
	sigaddset(&waitmask,SIGUSR1);
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGINT);

	if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)
		err_sys("SIG_BLOCK error");

	pr_mask("in critical region:");

	if(sigsuspend(&waitmask) != -1)
		err_sys("suspend error");

	pr_mask("after return from sigsuspend:");

	if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)
		err_sys("SIG_SETMASK error");

	pr_mask("program end:");
}

static void sig_int(int signo)
{
	pr_mask("in sig_int:");
}

4.函数sigqueue

使用排队信号必须做一下几个操作:

(1)使用sigaction函数安装信号处理程序时指定SA_SIGINFO标志。

(2)在sigaction结构的sa_sigaction成员中提供信号处理程序。

(3)使用sigqueue函数发送信号。

#include <signal.h>

int sigqueue(pid_t pid,int signo,const union sigval value);


5.信号名和编号

可以通过psignal函数可移植地打印与信号编号对应的字符串。

#include <signal.h>

void psignal(int signal,const char * msg);//字符串msg输入到标准错误流

如果只需要信号的字符描述部分,可以使用strsignal函数。

#include <string.h>

char *strsignal(int signo);

《UNIX环境高级编程》读书笔记之信号(2)

标签:unix环境高级编程

原文地址:http://blog.csdn.net/yao_wust/article/details/39995691

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!