`

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 字段则指定了对信号进行处理的各个选项,它们的意义如下表所示。

    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 函数不再重启动被中断的系统调用。
  • 大小: 35.6 KB
  • 大小: 29.8 KB
分享到:
评论

相关推荐

    Linux下信号介绍与函数

    最后,`sigqueue`和`rt_sigqueueinfo.doc`涉及到实时信号(Real-Time Signals)的排队和传递。`sigqueue()`和`rt_sigqueueinfo()`提供了更高级的信号传递机制,可以携带额外的数据,并确保信号按照队列顺序处理。 ...

    Linux信号基础知识

    - 信号处理情况分析:`sigaction`可以设定SA_SIGINFO标志,使得信号处理函数接收额外的信息,如信号的来源和详细信息。 - `sigaction`信号处理注册:通过`struct sigaction`结构体,用户可以指定信号处理函数、...

    Linux进程间通信-信号通信信号发送实例.pdf

    `sigaction`函数用于设置信号处理函数和信号行为,`sigqueue`则用于携带自定义数据发送信号。程序会持续等待信号并每两秒发送一次,附加的数据是字符串"other info"。 在实际应用中,信号通信可以结合其他IPC机制,...

    第13章 进程间通信.pdf

    - **sigqueue函数**:发送信号的同时可以附带额外的数据。 - 函数原型:`int sigqueue(pid_t pid, int sig, const union sigval val);` - **alarm函数**:设定定时器,定时发送 `SIGALRM` 信号。 - 函数原型:`...

    Unix程序设计基础第三讲.ppt

    `signal()`和`sigaction()`函数用于改变信号的动作,其中`sigaction()`提供了更强大的功能,可以解决早期`signal()`函数的一些不可靠问题,如处理过程中的信号重入。`alarm()`函数则可以设置定时器,触发特定信号。 ...

    Linux下进程间通信机制的探讨.pdf

    接收进程则通过`signal`或`sigaction`函数安装信号处理函数,以响应接收到的信号。信号处理函数执行完毕后,进程会返回到原来的执行流程。 2. **管道通信机制**:管道分为有名管道和匿名管道。有名管道是文件系统的...

    linux环境多线程出错处理的分析[归类].pdf

    此外,`sigaction()`函数用于设置信号处理函数,可以替代传统的`signal()`函数,因为它允许更精细的控制,如指定SA_RESTART标志来控制系统调用在信号处理后是否自动重试。 总的来说,Linux环境下的多线程错误处理...

    深入浅出:信号应用实例.pdf

    3. **发送信号**:可以使用`kill()`或更高级的`sigqueue()`函数来发送信号到目标进程。 对于某些信号,仅仅注册信号处理函数就足够了,例如设置信号的默认行为或者忽略该信号。此外,还可以通过信号集(`sigset_t`)...

    linux信号专题笔记.docx

    - **`sigaction()`函数**:提供更强大的信号处理功能,可以设置信号处理函数、信号掩码等。 - **`sigqueue()`函数**:用于发送携带数据的信号。 #### 信号发送 Linux提供了多种方式来发送信号: - **`kill()`函数...

    Linux信号——IBM教程

    - `sigaction()`:这是一种更为强大的信号安装函数,支持更多选项,例如传递额外信息给信号处理函数。 **信号发送** - `kill()`:最常用的信号发送函数之一,用于向指定进程发送信号。 - `raise()`:用于向进程...

    进程间通讯.doc,通讯,进程

    - **信号处理函数**:进程可以使用`signal()`或`sigaction()`来指定信号处理函数。`signal()`是旧的API,可能依赖于平台,而`sigaction()`是更现代且跨平台的接口,提供了更多的控制选项,如SA_NODEFER、SA_...

    linux线程启动

    - `sigaction`系统调用可以设置信号处理函数。 - `sigframe`结构体用于存储信号处理上下文。 #### 四、同步机制 1. **互斥锁**: - 互斥锁是一种常用的同步机制,用于保护临界区,防止多个线程同时访问同一资源...

    UNIX环境高级编程

    - **信号处理**:signal()、raise()、sigaction()等用于处理进程间的通信和异常情况。 3. **进程间通信(IPC)**: - **管道(pipe)**:半双工通信,数据只能单向流动。 - **命名管道(FIFO)**:允许不同进程...

    Linux编程技术-实验3 进程之间的通信.docx

    - 目标进程使用`signal()`或`sigaction()`函数捕获信号,并执行相应的处理逻辑。 - **代码示例**: ```c #include #include #include #include #include void handler(int sig) { switch (sig) { case ...

Global site tag (gtag.js) - Google Analytics