Linux0.11内核中的wait_on_buffer和wait_on_inode函数是非常有代表性的延迟性函数处理过程,网上关于这两个函数的讨论
也很多,最主要的一个问题是为什么要在判断b_lock之前关中断,这个问题也困扰了我很长时间,查了不少帖子,学到不少东西,但总是
觉得有些细节没有弄清楚,因此借着自己实践开发一个小OS的过程,研究了一下wait_on_buffer,还是学到不少东西的。贴出来,分享
给大家,欢迎讨论~
Linux0.11版函数定义:
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
分析如下:
1. 首先可以明确,wait_on_buffer是工作在内核态的函数。更进一步应当理解为两种可能性:
或者是当前某个用户态的进程请求数据进而引发的,那么可以认为是当前进程进入了内核态;又或者是内核本身的某个任务
引发的操作。不管怎样wait_on_buffer背后是代表这某个进程或者任务的。
2. wait_on_buffer中通过cli和sti起到一个保护临界区的作用,为什么这么说?
原因首先还在于wait_on_buffer是工作在内核态的环境下,此时cli就意味着关闭了所有的可屏蔽中断,如时钟中断和硬盘
处理中断等等,这也就意味着:
1)当前工作在用户态的进程不会因为时间片到了有可能被轮转出去,切换成其他的进程,从而保证while(bh->b_lock)形成的
若干条指令中间不会被打断,造成可能有别的进程修改了bh->b_lock的值,造成错误;
2)不会造成硬盘中断的到来引发的其他进程对bh->b_lock的操作,进而造成错误。
因此,通过关闭中断,可以达到while (bh->b_lock)语句在执行期间被他人修改,从而实现临界区的效果。
关于这一点,第3版的《Understanding the Linux Kernel》在第五章(内核同步)里明确也提到,确保一组内核语句被当作
一个临界区处理的主要机制之一就是中断禁止,可惜本人在上学时学的OS教材是理论性较强的那种,只关注了各种各样的临界操
作模型,没有提到实现机制,导致很长时间都觉得临界区的概念很虚,不好掌握。
3.还有一个重要的问题就是如果关闭了中断,那别的用户进程怎么办?是不是整个系统在这段时间内都不能收到相关的中断信号
了?这个问题也有很多人问,答案当然是不会影响其他的用户进程,原因在于sleep_on在将当前进程挂起后,会执行一次进程调
度操作,即schedule(),而一旦选择了新进程进行切换时,会将新进程的EFLAGS寄存器内容也加载到相应的寄存器的,而这里当
然包含了IF(Interrupt Flag)位,也就是说如果此时切换过来的进程是使用自己原先的中断开关状态的,原来的开就开,原来的关
就关,和之前的进程无关。因此,wait_on_buffer里对中断的操作,只影响当时的进程,故这个中断也被称为“本地中断”,这
个称呼更能反映其实质吧。