在Linux中接收SIGINT和异常处理

假设我们在C中有一个使用sleep()函数的程序

该程序执行并进入睡眠状态。然后,我们输入Ctrl+ C将SIGINT信号发送到该进程。

我们知道接收到SIGINT时的默认操作是终止该进程,我们也知道每当睡眠进程收到信号时,sleep()函数都会恢复该进程。

我的教科书上说,为了允许sleep()函数返回,我们必须安装一个SIGINT处理程序,如下所示:

void handler(int sig){

return; /* Catch the signal and return */

}

...

int main(int argc, char **argv) {

...

if (signal(SIGINT, handler) == SIG_ERR) /* Install SIGINT handler */

unix_error("signal error\n");

...

sleep(1000)

}

虽然代码看起来很简单,但是如果我想更深入地研究,我仍然有疑问:

背景:当进程处于hibernate状态时,我们键入Ctrl+ C发送SIGINT

问题1:我的理解是,内核通过更新在插入位向量中SIGINT的对应挂起位将SIGINT发送到进程,我的理解正确吗?

问题2:处理器检测到SIGINT的存在,但是由于我们覆盖了处理程序以使其返回而不是终止进程,因此我们的处理程序被执行,然后内核清除SIGINT的对应挂起位,我的理解正确吗?

Q3-由于SIGINT的相应挂起位被清除,那么sleep()函数如何返回?我认为应该仍然处于睡眠状态,因为从理论上讲,sleep()函数无法知道SIGINT的存在(已清除)

回答:

  • 内核检查进程是否阻塞了接收到的信号,如果是,它将更新进程条目中的挂起信号位(在具有可靠信号的系统上不可靠,这应该是一个计数器),以调用信号处理程序当信号再次被解除阻塞时(见下文)。如果未阻塞,则系统调用将准备返回值和errno值,并返回到用户模式,并在程序的虚拟堆栈中安装特殊代码,从而使该syscall代码在从通用代码返回之前调用信号处理程序(已在用户模式下)。系统调用返回给-1调用者代码,并且errno变量设置为EINTR。这要求该进程已安装信号处理程序,因为默认情况下该操作是中止该进程,因此它不会从正在等待的系统调用中返回。认为当说 内核 实际执行的代码在系统调用中时就被唤醒并通知特殊情况(接收到信号)中断的调用,检测到要调用信号处理程序,并准备用户堆栈跳转从syscall()包装返回之前,将其放置到适当的位置(用户代码中的中断处理程序)。

  • 挂起位 用于保存要调用的挂起信号处理程序,因此不是这种情况。在该过程的执行部分中,unix程序加载器在从系统调用返回之前,安装一些基本代码以跳转到信号处理程序。这是因为信号处理程序必须在用户模式下执行(而不是在内核模式下执行),所以一切都会在系统调用终止时发生。执行的信号处理程序是SIGINT,但被中断的代码是系统调用,在系统调用返回之前(返回代码和errno变量已经固定),什么也不会发生

  • 好吧,您的推论是基于错误的前提,也就是说, 中断待处理标志表明已接收到中断 。该位 预示着未处理中断已被标记为交付 ,而这只有在其他系统调用发生(解除阻塞信号)。一旦信号被解除阻塞,sigsetmask(2)系统调用的返回代码将执行信号处理程序。在这种情况下,信号将在计时器经过后立即传递到进程,系统调用将被中断,并且,如果您尚未为信号安装信号处理程序 SIGALRM(但sleep(2)实现则至少在以前这样做)实施)程序将被中止。

注意

当我说该程序被内核中止时,但在两种情况下,所涉及的信号(SIGINTSIGALRM)都不会使它转储核心文件。该程序被中止而不生成core

这与abort()发送a 的例程的行为不同SIGABRT,因此,它使de kernel转储进程的核心文件。

以上是 在Linux中接收SIGINT和异常处理 的全部内容, 来源链接: utcz.com/qa/419144.html

回到顶部