【发布时间】:2022-11-07 21:38:51
【问题描述】:
我读了几本关于信号的 Linux 书籍和教程,他们都说内核在内核从内核转换到用户模式的时间处理信号。这是完全有道理的,直到我看到并尝试了following code:
>cat sig_timing.c
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
volatile bool done = false;
static void sig_handler(int signo)
{
printf("Received signal %d (%s), current errno:%s\n", signo, strsignal(signo), strerror(errno));
done = true;
}
int main(int argc, char **argv)
{
signal(SIGALRM, sig_handler);
alarm(3);
while (!done) {
strlen("Hello World!");
}
return 0;
}
>gcc sig_timing.c
>./a.out
Received signal 14 (Alarm clock), current errno:Success
所以主函数注册信号后进入无限循环,循环没有调用任何系统调用,所以没有机会进入内核,那么就没有从内核态到用户态的转换,那么应该没有机会调用信号处理程序,对吧?
Later on,谈话主持人解释了发生了什么(我适应了一点):
Sender内核线程发送inter-cpu消息导致硬件 中断 CPU 运行目标进程,使其进入 内核处理中断,并返回用户模式。
我不太相信:这个解释似乎是说信号发送器和信号接收器在 2 个 CPU 硬件线程上运行。但是没有超线程的 CPU 呢?该进程仅在一个 CPU 线程上运行。在那种情况下,当用户土地代码运行无限循环时,信号是否有机会得到处理?
【问题讨论】:
-
当信号发生时,内核可以强制进程进入内核模式。
-
中断处理程序根本不在“线程”上运行。这是CPU的核心原理;当收到中断时,CPU暂停当前正在执行的线程(我确信它对于多核和超线程 CPU 来说更复杂)并且只运行中断处理程序。处理程序由内核注册;他们可以为所欲为。一个简单的例子是定时器中断。当您运行无限循环时,您的整个操作系统会崩溃吗?不,甚至在没有超线程的单核 CPU 上也不行。那是因为定时器中断处理程序仍然有效,所以调度程序仍然有效。
-
即使没有 inter-cpu 消息,线程仍然可以在其时间片到期时被调度程序抢占。
-
内核运行信号处理程序的方式与抢占进程运行另一个处理程序的方式相同:当从时钟接收到中断时,cpu 将运行中断处理程序而不是它正在执行的任何操作。这就是内核接管执行并调用处理程序的方式。
标签: c linux linux-kernel signals