现在的位置: 首页 > 综合 > 正文

启动大内核锁

2013年03月26日 ⁄ 综合 ⁄ 共 1159字 ⁄ 字号 评论关闭

5.1.2 启动大内核锁

回到start_kernel557行,lock_kernel(),实际的代码来了,大内核锁。我们在.config文件中配置了CONFIG_LOCK_KERNEL的,所以这个函数是start_kernel中继local_irq_disable之后实际执行到的第二个函数。

 

有关大内核的知识,这里又简单的介绍一下。在早期的Linux内核版本中,大内核锁(big kernel block,也叫全局内核锁或BKL)被广泛使用。在2.0版本中,这个锁是相对粗粒度的自旋锁,确保每次只有一个进程能运行在内核态。2.22.4内核具有极大的灵活性,不再依赖一个单独的自旋锁,而是由许多不同的自旋锁保护大量的内核数据结构。在Linux 2.6版本的内核中,用大内核锁来裸护旧的代码(绝大多数主要是与VFS和几个文件系统相关的函数)。

 

从内核版本2.6.11开始,用一个叫做kernel_sem的信号量来实现大内核锁(在较早的2.6版本中,大内核锁是通过自旋锁来实现的)。但是,大内核锁比简单的信号量要复杂一些。

 

每个进程描述符task_struct都含有lock_depth字段,其就是一个整形变量,这个字段允许同一个进程几次获取大内核锁。因此,对大内核锁两次连续的请求不挂起处理器(相对于普通自旋锁)。如果进程未获的过锁,则这个字段的值为-1;否则,这个字段的值加1,表示已经请求了多少次锁。lock_depth字段对中断处理程序、异常处理程序及可延迟函数获取大内核锁都是至关重要的。如果没有这个字段,那么,在当前进程已经拥有大内核锁的情况下,任何试图获得这个锁的异步函数都可能产生死锁。

 

lock_kernel ()unlock_kernel()内核函数用来获得和释放大内核锁。前一个函数等价于:

    depth = current->lock_depth + 1;

    if (depth == 0)

        down(&kernel_sem);

    current->lock_depth = depth;

 

而后者等价于

    if (--current->lock_depth < 0)

        up(&kernel_sem);

 

注意,lock_kernel()unlock_kernel()函数的if语句不需要原子地执行,因为lock_depth不是全局变量——这是每个CPU在自己当前进程描述符中访问的一个字段。在if语句确本地中断也不会引起竞争条件。即使新内核控制路径调用了lock_kernel(),它在终止前也必须释放大内核锁。

 

对内核同步与互斥机制还不熟悉的同学,请查看博客“同步与互斥的基本原理”。于是乎,后面肯定有会一个unlock_kernel函数跟557行的lock_kernel配对,咱们拭目以待。

抱歉!评论已关闭.