ZBLOG

sigaction sa

struct sigaction 是 Linux/Unix 系统中用于设置信号处理的关键数据结构,其定义和用法直接影响信号的行为。以下是详细解析:


1. struct sigaction 结构体定义

#include <signal.h>

struct sigaction {
    void     (*sa_handler)(int);      // 传统信号处理函数(如 SIG_DFL/SIG_IGN)
    void     (*sa_sigaction)(int, siginfo_t *, void *); // 扩展信号处理函数
    sigset_t sa_mask;                // 执行处理函数时要阻塞的信号集
    int      sa_flags;               // 控制信号行为的标志位
};

关键字段说明:

字段 作用
sa_handler 简单信号处理函数(如 SIG_DFLSIG_IGN 或自定义函数)
sa_sigaction 支持附加信息的信号处理函数(需设置 SA_SIGINFO
sa_mask 在执行当前处理函数时自动阻塞的信号集(防止重入)
sa_flags 控制信号行为(如 SA_RESTARTSA_SIGINFO

2. sa_flags 常用标志

标志 作用
SA_RESTART 自动重启被中断的系统调用(避免慢速调用因信号返回错误)
SA_SIGINFO 使用 sa_sigaction()(而非 sa_handler()),可获取更多信息
SA_NOCLDSTOP 子进程停止时不发送 SIGCHLD
SA_NODEFER/SA_NOMASK 不阻塞当前正在处理的信号(默认会阻塞,防止重入)

3. 典型用法示例

(1) 基本用法:捕获 SIGINT (Ctrl+C)

#include <signal.h>
#include <stdio.h>

void handler(int sig) {
    printf("Received SIGINT\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);   // 不额外阻塞其他信号
    sa.sa_flags = SA_RESTART;   // 重启被中断的系统调用

    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        return -1;
    }

    while(1); // Keep running to test signal
}

(2) 高级用法:获取信号的详细信息 (siginfo_t)

void handler(int sig, siginfo_t *info, void *ucontext) {
    printf("Signal %d from PID %d\n", info->si_signo, info->si_pid);
}

int main() {
    struct sigaction sa;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;   // Enable extended signal handling

    if (sigaction(SIGTERM, &sa, NULL) == -1) {
        perror("sigaction");
        return -1;
    }
}

4. system()中的特殊处理

在标准库的 system()实现中:

  • 临时忽略 SIGINT/SIGQUIT:
    防止用户在终端按 Ctrl+C (SIGINT)终止父进程。
  • 阻塞 SIGCHLD:
    避免子进程退出时与父进程的其他部分产生竞争条件。
// system()内部伪代码片段:
struct sigaction ignore_action;
ignore_action.sa_handler = SIG_IGN; 
sigemptyset(&ignore_action.sa_mask);
ignore_action.sa_flags = SA_RESTART;

// Ignore SIGINT and SIGQUIT during command execution
sigaction(SIGINT, &ignore_action, &old_int);
sigaction(SIGQUIT, &ignore_action, &old_quit);

// Block SIGCHLD to prevent race conditions
sigprocmask(SIG_BLOCK, &chld_set, &old_mask);

// ... fork() + exec() ...

// Restore original handlers and mask after execution completes.

5. FAQ

(1) Why block signals in sa_mask?

  • 防止重入问题:若在处理某个信号时,同一信号再次触发可能导致递归崩溃。
  • Example:
    若正在处理 SIGHUP,默认情况下新到达的 SIGHUP会被阻塞,直到当前处理完成。

(2)SA_RESTART vs SA_NODEFER:

  • ✅ Use SA_RESTART:
    适用于需要稳定运行的网络服务等场景。
  • ❌ Avoid for time-critical operations:
    某些系统调用不应被重启(如定时器相关)。

(3)siginfo_t *info: What’s inside?

typedef struct {
	int      si_signo;     /* Signal number */
	pid_t	  si_pid;      /* Sending process ID */
	void	  *si_addr;     /* Faulting memory address (e.g., for SIGSEGV)*/
} siginfo_t;

完整定义见 man sigaction(2).


6. Debugging Tips

(1) Check current signal handlers:

gdb -p <PID> 
(gdb) p *(struct sigaction*)0x7ffd12345678 # Examine a saved struct

# Or via /proc:
cat /proc/<PID>/status | grep SigCgt       # Hex mask of caught signals

(2) Trace signal modifications:

strace -e trace=rt_sig* ./your_program     # Monitor all signal syscalls 

掌握这些细节后,可以更精准地控制程序对信号的响应行为!


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23684

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?