我已阻止,然后通过以下代码等待信号:
sigset_t set;
sigfillset(&set); // all signals
sigprocmask(SIG_SETMASK, &set, NULL); // block all signals
siginfo_t info;
int signum = sigwaitinfo(&set, &info); // wait for next signal
struct sigaction act;
sigaction(signum, NULL, &act); // get the current handler for the signal
act.sa_handler(signum); // invoke it
最后一行生成分段错误,因为处理程序设置为SIG_DFL
(定义为0
)。如果设置为SIG_DFL
或SIG_IGN
,如何手动调用默认处理程序?另请注意,SIG_IGN
定义为1
。
答案 0 :(得分:2)
正如您所发现的那样,您无法调用SIG_DFL和SIG_IGN 本身。但是,你可以或多或少地模仿他们的行为。
简而言之,模仿正常的信号配置将是:
sa_handler
s 这样做你想要的吗?
#include <signal.h>
#include <stdlib.h>
/* Manually dispose of a signal, mimicking the behavior of current
* signal dispositions as best we can. We won't cause EINTR, for
* instance.
*
* FIXME: save and restore errno around the SIG_DFL logic and
* SIG_IGN/CHLD logic.
*/
void dispatch_signal(const int signo) {
int stop = 0;
sigset_t oset;
struct sigaction curact;
sigaction(signo, NULL, &curact);
/* SIG_IGN => noop or soak up child term/stop signals (for CHLD) */
if (SIG_IGN == curact.sa_handler) {
if (SIGCHLD == signo) {
int status;
while (waitpid(-1, &status, WNOHANG|WUNTRACED) > 0) {;}
}
return;
}
/* user defined => invoke it */
if (SIG_DFL != curact.sa_handler) {
curact.sa_handler(signo);
return;
}
/* SIG_DFL => let kernel handle it (mostly).
*
* We handle noop signals ourselves -- "Ign" and "Cont", which we
* can never intercept while stopped.
*/
if (SIGURG == signo || SIGWINCH == signo || SIGCONT == signo) return;
/* Unblock CONT if this is a "Stop" signal, so that we may later be
* woken up.
*/
stop = (SIGTSTP == signo || SIGTTIN == signo || SIGTTOU == signo);
if (stop) {
sigset_t sig_cont;
sigemptyset(&sig_cont);
sigaddset(&sig_cont, SIGCONT);
sigprocmask(SIG_UNBLOCK, &sig_cont, &oset);
}
/* Re-raise, letting the kernel do the work:
* - Set exit codes and corefiles for "Term" and "Core"
* - Halt us and signal WUNTRACED'ing parents for "Stop"
* - Do the right thing if we forgot to handle any special
* signals or signals yet to be introduced
*/
kill(getpid(), signo);
/* Re-block CONT, if needed */
if (stop) sigprocmask(SIG_SETMASK, &oset, NULL);
}
<强>更新强> (回应OP的优秀问题)
1:在sigwaitinfo之后插入这个插槽吗?
是。类似的东西:
... block signals ...
signo = sigwaitinfo(&set, &info);
dispatch_signal(signo);
2:为什么不提出SIG_IGN处理的那些信号,无论如何它们都会被忽略
用户空间中的noop比三个系统调用(重新提升,取消屏蔽,重新屏蔽)更有效。此外,CHLD在SIG_IGNored时具有特殊的语义。
3:为什么要特别对待SIGCHLD?
最初(检查答案编辑)我没有 - 在SIG_IGN案例中重新提出它, 因为IGNored CHLD signals tell the kernel to automatically reap children。
但是,我更改了它因为"natural" CHLD signals carry information about the terminated process(至少是PID,状态和真实的UID)。 用户生成的CHLD信号不具有相同的语义,在我的测试中, IGNoring它们不会导致2.6自动恢复其SIGCHLD的排队僵尸 被“错过了”。所以,我自己做。
4:为什么“停止”相关信号解锁CONT。不会调用CONT的默认处理程序来取消停止进程吗?
如果我们停止(未执行)并且CONT被阻止,我们将永远不会收到 发信号唤醒我们!
5:为什么不调用加注而不是你给的杀线?
个人偏好; raise()
也可以。
答案 1 :(得分:1)
我在你的代码中看到2个错误:
1)你应该像这样反转最后两行:
act.sa_handler(signum);
sigaction(signum, NULL, &act);
2)您必须将函数处理程序传递给fiedl sa_handler而不是int。函数shoudl的原型如下所示:
/**
*some where in you code
*/
void handler (int signal){ /*your code*/}
/**
*
*/
act.sa_handler = handler;
如果要调用默认处理程序,则应将字段 sa_handler 设置为 SIG_DFL ,它应该可以正常工作。
答案 2 :(得分:1)
我不知道如何做到这一点。
我的唯一建议是查看man 7 signal
并根据您在那里看到的表格手动执行操作。 Ign
没什么。 Core
致电abort()
。 Term
为_exit()
。
当然,您也可以将信号处理程序设置回SIG_DFL,然后设置为kill(getpid(),THE_SIG)
(或等效的raise(THE_SIG)
)。 (我个人不喜欢raise
,因为在某些系统上它可能会在stderr上产生一些消息。)