dar*_*dar 34 kernel signals system-calls architecture
从阅读read()
和write()
调用上的手册页来看,这些调用似乎会被信号中断,无论它们是否必须阻塞。
特别地,假设
O_NONBLOCK
没有设置(即在阻塞模式下运行)read()
系统调用以从设备读取,结果在内核空间中执行内核控制路径。read()
在内核空间中执行时,先前为其安装处理程序的信号被传递到该进程并调用其信号处理程序。阅读SUSv3 'System Interfaces volume (XSH)' 中的手册页和相应部分,您会发现:
一世。如果 aread()
在读取任何数据之前被信号中断(即它必须阻塞,因为没有数据可用),它返回 -1 并errno
设置为 [EINTR]。
ii. 如果 aread()
在成功读取一些数据后被信号中断(即可以立即开始服务请求),它返回读取的字节数。
问题 A):
我是否正确地假设在任何一种情况下(阻止/不阻止)信号的传递和处理对read()
?
案例一。似乎可以理解,因为阻塞read()
通常会将进程置于TASK_INTERRUPTIBLE
状态,以便在传递信号时,内核将进程置于TASK_RUNNING
状态。
但是,当read()
不需要阻塞(情况 ii.)并且正在内核空间中处理请求时,我会认为信号的到达及其处理将是透明的,就像硬件的到达和正确处理一样中断会。特别是我会假设,在传递信号时,进程将被临时置于用户模式以执行其信号处理程序,它最终将从该处理程序返回以完成处理中断的read()
(在内核空间中),以便read()
运行其过程完成之后,进程返回到调用read()
(在用户空间中)之后的点,结果读取所有可用字节。
但是二。似乎暗示read()
被中断,因为数据立即可用,但它返回仅返回部分数据(而不是全部)。
这让我想到了我的第二个(也是最后一个)问题:
问题 B):
如果我在 A) 下的假设是正确的,为什么会read()
被中断,即使它不需要阻塞,因为有数据可以立即满足请求?换句话说,为什么read()
在执行信号处理程序后没有恢复,最终导致所有可用数据(毕竟可用)被返回?
Gil*_*il' 35
总结:您是正确的,接收信号是不透明的,无论是在 i(在没有读取任何东西的情况下中断)还是在 ii(在部分读取后中断)。否则,如果我需要对操作系统的架构和应用程序的架构进行根本性的改变。
考虑如果系统调用被信号中断会发生什么。信号处理程序将执行用户模式代码。但是系统调用处理程序是内核代码,不信任任何用户模式代码。因此,让我们探索系统调用处理程序的选择:
与中断的主要区别在于中断代码是可信的,并且受到高度约束。通常不允许分配资源,或永远运行,或获取锁而不释放它们,或做任何其他讨厌的事情;由于中断处理程序是由操作系统实现者自己编写的,他知道它不会做任何坏事。另一方面,应用程序代码可以做任何事情。
当应用程序在系统调用中途中断时,系统调用是否应该继续完成?不总是。例如,考虑一个类似 shell 的程序,它从终端读取一行,用户按下Ctrl+C
,触发 SIGINT。读取不能完成,这就是信号的全部内容。请注意,此示例表明read
即使尚未读取任何字节,系统调用也必须是可中断的。
所以应用程序必须有一种方法告诉内核取消系统调用。在 unix 设计下,这会自动发生:信号使系统调用返回。其他设计需要应用程序自行恢复或取消系统调用的方法。
该read
系统调用的方式,是因为它是有道理的原始,由于操作系统的通用设计。粗略地说,它的意思是“尽可能多地读取,达到限制(缓冲区大小),但如果发生其他事情则停止”。实际读取一个完整的缓冲区涉及read
在循环中运行,直到读取了尽可能多的字节;这是一个更高级别的函数,fread(3)
。与read(2)
系统调用不同的是,它fread
是一个库函数,在read
. 它适用于读取文件或尝试死亡的应用程序;它不适合命令行解释器或必须干净地限制连接的网络程序,也不适合具有并发连接且不使用线程的网络程序。
Robert Love 的 Linux System Programming 中提供了循环读取的示例:
ssize_t ret;
while (len != 0 && (ret = read (fd, buf, len)) != 0) {
if (ret == -1) {
if (errno == EINTR)
continue;
perror ("read");
break;
}
len -= ret;
buf += ret;
}
Run Code Online (Sandbox Code Playgroud)
它关心case i
和case ii
和几个。
归档时间: |
|
查看次数: |
26496 次 |
最近记录: |