sigaction 和 sigqueue 函数

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

#include <signal.h>
int sigaction(int signo,const struct sigaction *restrict act,struct sigaction *restrict oact);
/* 返回值:若成功,返回 0;否则,返回 -1 */

struct sigaction{
void (*sa_handler)(int); // addr of signal handler, or SIG_IGN, or SIG_DFL
sigset_t sa_mask; // additional signals to block
int sa_flags; // signal options, Figure 10.16
void (*sa_sigaction)(int signo, siginfo_t *info, void *context); // alternate handler
};

typedef siginfo siginfo_t;
struct siginfo{
int si_signo; // signal number
int si_errno; // if nonzero, errno value from <errno.h>
int si_code; // additional info (depends on signal)
pid_t si_pid; // sending process ID
uid_t si_uid; // sending process real user ID
void *si_addr; // address that caused the fault
int si_status; // exit value or signal number
union sigval si_value; // application-specific value
/* possibly other fields also */
};
union sigval{
int sival_int;
void *sival_ptr;
};

struct ucontext_t{
ucontext_t *uc_link; // pointer to context context resumed when this context returns
sigset_t uc_sigmask; // signals blocks when this context is active
stack_t uc_stack; // stack used by this context
mcontext_t uc_mcontext; // machine-specific representation of saved context
};
struct stack_t{
void *ss_sp; // stack base or pointer
size_t ss_size; // stack size
int ss_flags; // flags
};

其中,参数 signo 是要检测或修改其具体动作的信号编号;若 act 指针非空,则指定要修改的动作;若 oact 指针非空,则系统用其返回该信号的上一个动作。一旦对给定的信号设置了一个动作,那么在调用 sigaction 显示地改变它之前,该设置就一直有效。
在 sigaction 结构中,当更改信号动作时,如果 sa_handler 字段包含一个信号捕捉函数的地址(不是 SIG_IGN 或 SIG_DFL),则在调用该捕捉函数前,sa_mask 字段说明的信号集将被加到进程的信号屏蔽字中,仅当从捕捉函数返回后再恢复进程的信号屏蔽字。这样,在调用信号处理程序时就能阻塞某些信号,此时操作系统建立的新信号屏蔽字还包括正被递送的信号,因此保证了在处理一个给定的信号时,如果这种信号再次发生,则它会被阻塞到对前一个信号的处理结束为止。sa_flags 字段则指定了对信号进行处理的各个选项,它们的意义如下表所示。
[img]http://dl2.iteye.com/upload/attachment/0127/2473/49bb2ef2-347d-386a-a4b1-ecb449fcd36f.png[/img]
sa_sigaction 字段是一个替代的信号处理程序,当 sa_flags 指定了 SA_SIGINFO 标志时就会使用该信号处理程序。当实现支持实时信号扩展时,用 SA_SIGINFO 标志建立的信号处理程序将造成信号可靠地排队。一些保留信号可由实时应用使用。如果信号由 sigqueue 函数产生,则 siginfo 结构能包含应用特有的数据。
siginfo 结构包含了信号产生原因的有关信息,符合 POSIX.1 的所有实现必须至少包括 si_signo 和 si_code 成员。应用程序在递送信号时,在 si_value.sival_int 中传递一个整型数或者在 si_value.sival_ptr 中传递一个指针值。下表显示了对各种信号的 si_code 值(这些信号是由 Single UNIX Specification 定义的,实现也可定义附加的代码值)。
[img]http://dl2.iteye.com/upload/attachment/0127/2489/2517fd4a-94d6-3684-bdbd-d5ccafd1b65c.png[/img]
若信号是 SIGCHLD,则将设置 si_pid、si_status 和 si_uid 字段。若信号是 SIGBUS、SIGILL、SIGFPE 或 SIGSEGV,则 si_addr 包含造成故障的根源地址,不过可能并不准确。si_errno 包含错误编号,它对应造成信号产生的条件,并由实现定义。
信号处理程序的 context 参数可被强制类型转换为 ucontext_t 结构类型,该结构标识信号传递时进程的上下文。uc_stack 字段描述了当前上下文使用的栈。

大部分 UNIX 系统不对信号排队,但在 POSIX.1 的实时扩展中,有些系统开始增加对信号排队的支持。通常一个信号带有一个位信息:信号本身。除了对该信号排队以外,这些扩展允许应用程序在递交信号时传递更多的信息,这些信息嵌入在 siginfo 结构中。除了系统提供的信息,应用程序还可以向信号处理程序传递整数或者指向包含更多信息的缓冲区指针。
使用排队信号必须做以下几个操作。
(1)使用 sigaction 函数安装信号处理程序时指定 SA_SIGINFO 标志。如果没有给出该标志,信号会延迟,但信号是否进入队列要取决于具体实现。
(2)在 sigaction 结构的 sa_sigaction 成员(而不是通常的 sa_handler)中提供信号处理程序。实现可能允许用户使用 sa_handler 字段,但不能获取 sigqueue 函数发送出来的额外信息。
(3)使用 sigqueue 函数发送信号。

#include <signal.h>
int sigqueue(pid_t pid, int signo, const union sigval value);
/* 返回值:若成功,返回 0;否则,返回 -1 */

信号不能被无限排队,到达 SIGQUEUE_MAX 限制后 sigqueue 就会失败,并将 errno 设为 EAGAIN。
下面是用 sigaction 函数实现的 signal 函数(可以通过指定 SA_RESETHAND 和 SA_NODEFER 选项以实现老的不可靠信号语义的 signal 函数)。

#include <signal.h>

typedef void Sigfunc(int);

// Reliable version of signal(), using POSIX.1 sigaction().
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;
}

/* sianal 函数的另一种版本,它力图阻止被中断的系统调用重启动。 */
Sigfunc *signal_intr(int signo, Sigfunc *func){
struct sigaction act, oact;

act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if(sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
}

这里,对除 SIGALRM 以外的所有信号都有意尝试设置 SA_RESTART 标志,于是被这些信号中断的系统调用都能自动重启动。不希望重启动 SIGALRM 中断的系统调用的原因是:希望对慢速 I/O 操作可以使用 alarm 函数设置时间限制。另外,某些早期系统(如 SunOS)定义了 SA_INTERRUPT 标志,这些系统的默认方式是重启动被中断的系统调用,而指定此标志就可以使其不再重启动。XSI 扩展规定,除非说明了 SA_RESTART 标志,否则 sigaction 函数不再重启动被中断的系统调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值