我知道当我们点击Ctrl + C时,会产生一个SIGINT信号,并且终止进程的默认动作将由内核完成。 但是这个终止的代码来自哪里呢? 它是在ELF二进制文件还是内核为我们做? 我认为它是在内核中,这就是为什么我们需要在我们的源代码中的自定义处理程序来覆盖信号的行为。
任何指针将不胜感激。
这是内核正在为我们做的事情。 您可以通过在内核源文件中读取signal.c
文件来找到所有的信息。
内核试图找到注册信号处理程序的地方从这里开始: http : //lxr.free-electrons.com/source/kernel/signal.c#L2257
2257 ka = &sighand->action[signr-1]; 2258 2259 /* Trace actually delivered signals. */ 2260 trace_signal_deliver(signr, &ksig->info, ka); 2261 2262 if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ 2263 continue; 2264 if (ka->sa.sa_handler != SIG_DFL) { 2265 /* Run the handler. */ 2266 ksig->ka = *ka; 2267 2268 if (ka->sa.sa_flags & SA_ONESHOT) 2269 ka->sa.sa_handler = SIG_DFL; 2270 2271 break; /* will return non-zero "signr" value */ 2272 }
所以,如果有一个信号处理程序,如果它不是“忽略信号”( SIG_IGN
),并且如果它不是“默认”处理程序( SIG_DEF
),内核将简单地标记为运行(并且,如果它是一次性的将处理程序再次移到默认处理程序)
但是,如果没有注册信号处理程序,或者如果它是SIG_DEF
,内核会检查是否需要暂停进程,最后内核会声明以下内容:
2330 /* 2331 * Anything else is fatal, maybe with a core dump. 2332 */
假设你kill(theShell, SIGINT)
。 发生的事情就像…(不显示内核代码,因为它实际上并不相关)
sys_kill()
,然后继续执行执行原始系统调用的汇编代码。 SIG_DEF
,则内核将直接执行相应的默认操作并返回。 如果进程将相应的信号处理程序设置为SIG_IGN
,则该信号将被忽略,系统调用返回。 否则,继续。 -EINTR
(为了简单起见),并调用处理程序。 处理程序返回后,会自动调用系统调用sys_sigreturn
,在信号之前恢复线程的状态。 5
发生, kill()
进程的系统调用返回。