- 浏览: 141180 次
文章分类
最新评论
sigaction 函数的功能是检查或修改与指定信号相关联的处理动作。
其中,参数 signo 是要检测或修改其具体动作的信号编号;若 act 指针非空,则指定要修改的动作;若 oact 指针非空,则系统用其返回该信号的上一个动作。一旦对给定的信号设置了一个动作,那么在调用 sigaction 显示地改变它之前,该设置就一直有效。
在 sigaction 结构中,当更改信号动作时,如果 sa_handler 字段包含一个信号捕捉函数的地址(不是 SIG_IGN 或 SIG_DFL),则在调用该捕捉函数前,sa_mask 字段说明的信号集将被加到进程的信号屏蔽字中,仅当从捕捉函数返回后再恢复进程的信号屏蔽字。这样,在调用信号处理程序时就能阻塞某些信号,此时操作系统建立的新信号屏蔽字还包括正被递送的信号,因此保证了在处理一个给定的信号时,如果这种信号再次发生,则它会被阻塞到对前一个信号的处理结束为止。sa_flags 字段则指定了对信号进行处理的各个选项,它们的意义如下表所示。
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 定义的,实现也可定义附加的代码值)。
若信号是 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 函数发送信号。
信号不能被无限排队,到达 SIGQUEUE_MAX 限制后 sigqueue 就会失败,并将 errno 设为 EAGAIN。
下面是用 sigaction 函数实现的 signal 函数(可以通过指定 SA_RESETHAND 和 SA_NODEFER 选项以实现老的不可靠信号语义的 signal 函数)。
这里,对除 SIGALRM 以外的所有信号都有意尝试设置 SA_RESTART 标志,于是被这些信号中断的系统调用都能自动重启动。不希望重启动 SIGALRM 中断的系统调用的原因是:希望对慢速 I/O 操作可以使用 alarm 函数设置时间限制。另外,某些早期系统(如 SunOS)定义了 SA_INTERRUPT 标志,这些系统的默认方式是重启动被中断的系统调用,而指定此标志就可以使其不再重启动。XSI 扩展规定,除非说明了 SA_RESTART 标志,否则 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 字段则指定了对信号进行处理的各个选项,它们的意义如下表所示。
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 定义的,实现也可定义附加的代码值)。
若信号是 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 函数不再重启动被中断的系统调用。
发表评论
-
打开伪终端设备
2018-07-09 20:50 1249在伪终端概述一节中已对 PTY进行了初步的介绍。尽管 ... -
伪终端概述
2018-06-02 11:05 1538伪终端就是指,一个应用程序看上去像一个终端,但事实上它 ... -
终端窗口大小和 termcap
2018-05-29 22:39 792多数 UNIX 系统都提供了一种跟踪当前终端窗口大小的 ... -
终端规范模式和非规范模式
2018-05-29 00:25 944终端规范模式很简单:发一个读请求,当一行已经输入后,终 ... -
终端标识
2018-05-23 11:18 567尽管控制终端的名字在多数 UNIX 系统上都是 /de ... -
波特率和行控制函数
2018-05-22 07:53 936虽然大多数终端设 ... -
终端属性和选项标志
2018-05-20 07:40 707tcgetattr 和 tcsetattr ... -
终端特殊输入字符
2018-05-17 06:33 810终端支持下表所示的特殊输入字符。 为了更改 ... -
终端 I/O 综述
2018-05-10 07:56 434终端设备可认为是由内核中的终端驱动程序控制的。每个终端 ... -
POSIX 信号量
2018-05-09 00:03 576在XSI IPC通信之信 ... -
XSI IPC 通信之共享存储
2018-04-25 07:18 944在XSI IPC通信之消息队列和XSI IPC通信之信 ... -
XSI IPC通信之信号量
2018-04-17 23:38 613在XSI IPC通信之消 ... -
XSI IPC通信之消息队列
2018-04-15 10:54 490消息队列是消息的链接表,存储在内核中,由消息队列标识符 ... -
XSI IPC 相似特征介绍
2018-02-08 23:48 481有 3 种称作 XSI IPC ... -
IPC 通信之 FIFO
2018-02-06 22:55 413FIFO 也被称为命名管道,未命名的管道只能在两个相关 ... -
IPC 通信之管道
2018-01-30 22:22 383管道是 UNIX 系统 IPC 的最古老但也是最常用的 ... -
readv/writev 函数及存储映射 I/O
2018-01-19 00:57 879readv 和 writev 函数可用于在一次函数调用 ... -
POSIX 异步 I/O
2018-01-16 21:33 452POSIX 异步 I/O 接口为对不同类型的文件进行异 ... -
fcntl 记录锁
2018-01-06 23:48 588记录锁的功能是:当有进程正在读或修改文件的某个部分时, ... -
守护进程惯例
2018-01-06 23:52 433UNIX 系统中,守护进程遵循下列通用惯例。 ...
相关推荐
最后,`sigqueue`和`rt_sigqueueinfo.doc`涉及到实时信号(Real-Time Signals)的排队和传递。`sigqueue()`和`rt_sigqueueinfo()`提供了更高级的信号传递机制,可以携带额外的数据,并确保信号按照队列顺序处理。 ...
- 信号处理情况分析:`sigaction`可以设定SA_SIGINFO标志,使得信号处理函数接收额外的信息,如信号的来源和详细信息。 - `sigaction`信号处理注册:通过`struct sigaction`结构体,用户可以指定信号处理函数、...
`sigaction`函数用于设置信号处理函数和信号行为,`sigqueue`则用于携带自定义数据发送信号。程序会持续等待信号并每两秒发送一次,附加的数据是字符串"other info"。 在实际应用中,信号通信可以结合其他IPC机制,...
- **sigqueue函数**:发送信号的同时可以附带额外的数据。 - 函数原型:`int sigqueue(pid_t pid, int sig, const union sigval val);` - **alarm函数**:设定定时器,定时发送 `SIGALRM` 信号。 - 函数原型:`...
`signal()`和`sigaction()`函数用于改变信号的动作,其中`sigaction()`提供了更强大的功能,可以解决早期`signal()`函数的一些不可靠问题,如处理过程中的信号重入。`alarm()`函数则可以设置定时器,触发特定信号。 ...
接收进程则通过`signal`或`sigaction`函数安装信号处理函数,以响应接收到的信号。信号处理函数执行完毕后,进程会返回到原来的执行流程。 2. **管道通信机制**:管道分为有名管道和匿名管道。有名管道是文件系统的...
此外,`sigaction()`函数用于设置信号处理函数,可以替代传统的`signal()`函数,因为它允许更精细的控制,如指定SA_RESTART标志来控制系统调用在信号处理后是否自动重试。 总的来说,Linux环境下的多线程错误处理...
3. **发送信号**:可以使用`kill()`或更高级的`sigqueue()`函数来发送信号到目标进程。 对于某些信号,仅仅注册信号处理函数就足够了,例如设置信号的默认行为或者忽略该信号。此外,还可以通过信号集(`sigset_t`)...
- **`sigaction()`函数**:提供更强大的信号处理功能,可以设置信号处理函数、信号掩码等。 - **`sigqueue()`函数**:用于发送携带数据的信号。 #### 信号发送 Linux提供了多种方式来发送信号: - **`kill()`函数...
- `sigaction()`:这是一种更为强大的信号安装函数,支持更多选项,例如传递额外信息给信号处理函数。 **信号发送** - `kill()`:最常用的信号发送函数之一,用于向指定进程发送信号。 - `raise()`:用于向进程...
- **信号处理函数**:进程可以使用`signal()`或`sigaction()`来指定信号处理函数。`signal()`是旧的API,可能依赖于平台,而`sigaction()`是更现代且跨平台的接口,提供了更多的控制选项,如SA_NODEFER、SA_...
- `sigaction`系统调用可以设置信号处理函数。 - `sigframe`结构体用于存储信号处理上下文。 #### 四、同步机制 1. **互斥锁**: - 互斥锁是一种常用的同步机制,用于保护临界区,防止多个线程同时访问同一资源...
- **信号处理**:signal()、raise()、sigaction()等用于处理进程间的通信和异常情况。 3. **进程间通信(IPC)**: - **管道(pipe)**:半双工通信,数据只能单向流动。 - **命名管道(FIFO)**:允许不同进程...
- 目标进程使用`signal()`或`sigaction()`函数捕获信号,并执行相应的处理逻辑。 - **代码示例**: ```c #include #include #include #include #include void handler(int sig) { switch (sig) { case ...