嵌入式Linux系统编程学习之十五sigaction信号处理机制


一、信号处理情况分析

  在 signal 处理机制下,还有许多特殊情况需要考虑:

  • 注册一个信号处理函数,并且处理完毕一个信号之后,是否需要重新注册,才能够捕捉下一个信号?(不需要)
  • 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个同类型的信号,这时该怎么处理?(挨着执行)
  • 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个不同类型的信号,这时怎么处理?(跳转去执行另一个信号,之后再执行剩下的没有处理完的信号)
  • 如果程序阻塞在一个系统调用(如 read(…) )上时,发生了一个信号,这时是让系统调用返回错误,再接着进入信号处理函数,还是先跳转到信号处理函数?(等信号处理完毕后,系统再调用返回)

二、sigaction 信号处理注册

sigaction 函数原型为:

	#include <signal.h>
	int sigaction(int signum, const struct sigaction * act, struct sigaction * oldact);

  sigaction 也用于注册一个信号处理函数。
  参数 signum 为需要捕捉的信号;
  参数 act 是一个结构体,里面包含信号处理函数地址、处理方式等信息;
  参数 oldact 是一个传出参数,sigaction 函数调用成功后,oldact 里面包含以前对 signum 的处理方式的信息,通常为 NULL。
  如果调用成功,将返回 0,否则返回 -1。

结构体 struct sigaction(注意名称与函数 sigaction 相同)的原型为:

	struct sigaction {
		void( *sa_handler)(int);						//老类型的信号处理函数指针
		void( *sa_sigaction)(int, siginfo_t *, void *);	//新类型的信号处理函数指针
		sigset_t sa_mask;								//将要被阻塞的信号集合
		int sa_flags;									//信号处理方式掩码(=>SA_SIGINFO)
		void( *sa_restorer)(void);						//保留,不使用
	};

  该结构体的各字段含义及使用方式:
 (1)字段 sa_handler 是一个函数指针,用于指向原型为 void handler(int) 的信号处理函数地址,即老类型的信号处理函数(如果用这个再将 sa_flags=0,就等同于 signal() 函数)。
 (2)字段 sa_sigaction 也是一个函数指针,用于指向原型为:
  void handler(int iSignNum, siginfo_t * pSignInfo, void * pReserved)
  的信号处理函数,即新类型的信号处理函数,该函数的三个参数含义为:
   iSignNum 为传入的信号;
   pSignInfo 为与该信号相关的一些信息,是个结构体;
   pReserved 保留,暂时无用,通常为 NULL。
 (3)字段 sa_handler 和 sa_signaction 只应该有一个生效,如果想采用老的信号处理机制,就应该让 sa_handler 指向正确的信号处理函数,并且让字段 sa_flags 为 0 ;否则应该让 sa_sigaction 指向正确的信号处理函数,并且让字段 sa_flags 包含 SA_SIGINFO 选项。
 (4)字段 sa_mask 是一个包含信号集合的结构体,该结构体内的信号表示正在进行信号处理时,将要被阻塞的信号。针对 sigset_t 结构体,有一组专门的函数对它进行处理,它们是:

	#include <signal.h>
	int sigemptyset(sigset_t * set);					//清空信号集合 set
	int sigfillset(sigset_t * set);						//将所有信号填充进 set 中
	int sigaddset(sigset_t * set, int signum);			//往 set 中添加信号 signum
	int sigdelset(sigset_t * set, int signum);			//从 set 中移除信号 signum
	int sigismember(const sigset_t * set, int signum);	//判断 signum 是不是包含在 set 中
	int sigpending(sigset_t * set);						//将被阻塞的信号集合由参数 set 指针返回

  例如,在处理信号 SIGINT 时,只阻塞对 SIGQUIT 信号的处理,可以用如下方法:

	struct sigaction act;
	act.sa_flags=SA_SIGINFO;
	ac.sa_sigaction=newHandler;
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask, SIGQUIT);
	sigaction(SIGINT, &act, NULL);

 (5)字段 sa_flags 是一组掩码的合成值,指示信号处理时所应该采取的一些行为,各掩码的含义如下:

掩码描述
SA_RESETHAND处理完要捕捉的信号后,将自动撤销信号处理函数的注册,即必须再重新注册信号处理函数,才能继续处理接下来产生的信号。该选项不符合一般的信号处理流程,现已被废弃
SA_NODEFER在处理信号时,如果又发生了其他的信号,则立即进入其他信号的处理,等其他信号处理完毕后,再继续处理当前信号,即递归地处理。如果 sa_flags 包含了该掩码,则结构体 sigaction 的 sa_mask 将无效,不常用
SA_RESTART如果在发生信号时,程序正阻塞在某个系统调用中,例如,调用 read() 函数,则在处理完信号后,接着从阻塞的系统返回。如果不指定该参数,中断处理完毕之后,read 函数读取失败
SA_SIGINFO指示结构体的信号处理函数指针哪个有效,如果 sa_flags 包含该掩码,则 sa_sigaction 指针有效,否则 sa_handler 指针有效,常用

三、sigprocmask 信号阻塞

  函数 sigaction 中设置的被阻塞信号集合只是针对于要处理的信号,例如:

	struct sigaction act;
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask, SIGQUIT);
	sigaction(SIGINT, &act, NULL);

  表示只有在处理信号 SIGINT 时,才阻塞信号 SIGQUIT。

  函数 sigprocmask 是全程阻塞,在 sigprocmask 中设置了阻塞集合后,被阻塞的信号将不能再被信号处理函数捕捉,直到重新设置阻塞信号集合,它的原型为:

	#include <signal.h>
	int sigprocmask(int how, const sigset_t * set, sigset_t * oldset);

  参数 how 的值为如下 3 者之一:

  • SIG_BLOCK,将参数 2 的信号集合添加到进程原有的阻塞信号集合中。
  • SIG_UNBLOCK,从进程原有的阻塞信号集合移除参数 2 中包含的信号。
  • SIG_SETMASK,重新设置进程的阻塞信号集为参数 2 的信号集。
      参数 set 为阻塞信号集;
      参数 oldset 是传出参数,存放进程原有的信号集,通常为 NULL。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值