Linux 系统调用实现如何处理捕获的信号?

Linux 系统调用实现如何处理捕获的信号?

我了解信号的一般工作原理,并且我了解系统调用正在将任务状态更改为TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE防止关键部分的信号中断。现在我试图了解当任务状态是TASK_INTERRUPTIBLE并且在系统调用期间捕获信号时会发生什么。

我的问题如下:

  • 系统调用实现(例如read())如何处理信号。例如,在 的情况下read(),假设我们位于 ext2 文件系统驱动程序中的读取函数内。该函数是否每次都会检查是否有信号发生?因为它需要释放它分配的资源和/或解锁它获得的锁。总而言之,我的问题是系统调用实现(包括调用内核和驱动程序中的许多不同函数)如何知道信号已发生并释放它分配的资源?

  • 如果系统调用正在等待互斥锁可用(任务被阻止)并且发生信号,那么内核如何通知互斥锁的调用函数lock()它没有被锁定,但发生了信号?

  • 假设在read()ext2 驱动程序的函数执行期间发生了一个信号。 VFS 层和主系统调用函数 ( read()) 如何知道 ext2 驱动程序读取函数因信号而失败。他们都有必要的检查吗?不是要做很多检查吗?

答案1

系统调用实现(例如 read())如何处理信号。

好吧,这可能是误解的一部分,我们经常谈论系统调用,就好像它们是一件事一样,但实际上通常通过 stdlib 来实现用户空间接口。内核空间部分,即完成系统调用工作的部分,是运行内核代码的内核线程。内核线程不遵循与用户空间线程相同的规则,信号会排队并可能合并,甚至可能不会被传递。

...例如,在 read() 的情况下,假设我们位于 ext2 文件系统驱动程序中的读取函数内。该函数是否每次都会检查是否有信号发生?因为它需要释放它分配的资源和/或解锁它获得的锁。总而言之,我的问题是系统调用实现(包括调用内核和驱动程序中的许多不同函数)如何知道信号已发生并释放它分配的资源?

它不需要,因为文件系统代码将作为没有信号的内核线程运行。无论如何,您的系统调用很可能不会立即触发内核操作,而是排队等待工作线程完成。在这种情况下,线程通常会在等待 I/O 完成的同时处理信号,这是可中断的行为。请注意,这发生在运行系统调用的上下文之外的用户空间中。内核线程不会部分响应系统调用,因为它们所做的事情在奇怪的上下文中保存和恢复很复杂。

如果系统调用正在等待互斥锁可用(任务被阻止)并且发生信号,那么内核如何通知互斥锁 lock() 的调用函数它没有被锁定,但发生了信号?

这不应该发生在信号排队的内核空间中。使用信号保护用户空间代码免受不安全情况的影响非常重要,因此应用程序需要编写以确定它是否是一个问题以及如何修复它。

假设在执行 ext2 驱动程序的 read() 函数期间发生了一个信号。 VFS 层和主系统调用函数 (read()) 如何知道 ext2 驱动程序读取函数因信号而失败。他们都有必要的检查吗?不是要做很多检查吗?

它不会,因为它不会失败,因为内核进程不对信号起作用。它将排队直到控制权返回到收到信号的用户空间进程。

也可以看看:

内核中如何处理信号

这可能是一个骗局。

相关内容