以文本方式查看主题 - 曙海教育集团论坛 (http://peixun0.cn/bbs/index.asp) -- Linux驱动开发 (http://peixun0.cn/bbs/list.asp?boardid=33) ---- Linux驱动开发必看详解神秘内核 (http://peixun0.cn/bbs/dispbbs.asp?boardid=33&id=1705) |
-- 作者:wangxinxin -- 发布时间:2010-11-24 9:22:50 -- Linux驱动开发必看详解神秘内核 相关阅读: Fedora下内核编译 互斥体接口代替了旧的信号量接口(semaphore)。互斥体接口是从-rt树演化而来的,在2.6.16内核中被融入主线内核。 尽管如此,但是旧的信号量仍然在内核和驱动程序中广泛使用。信号量接口的基本用法如下: #include <asm/semaphore.h> /* Architecture dependent header */ /* Statically declare a semaphore. To dynamically down(&mysem); /* Acquire the semaphore */ /* ... Critical Section code ... */ up(&mysem); /* Release the semaphore */ 1. 案例1:进程上下文,单CPU,非抢占内核 这种情况最为简单,不需要加锁,因此不再赘述。 2. 案例2:进程和中断上下文,单CPU,非抢占内核 在这种情况下,为了保护临界区,仅仅需要禁止中断。如图2-4所示,假定进程上下文的执行单元A、B以及中断上下文的执行单元C都企图进入相同的临界区。
由于执行单元C总是在中断上下文执行,它会优先于执行单元A和B,因此,它不用担心保护的问题。执行单元A和B也不必关心彼此会被互相打断,因为内核是非抢占的。因此,执行单元A和B仅仅需要担心C会在它们进入临界区的时候强行进入。为了实现此目的,它们会在进入临界区之前禁止中断: Point A: 但是,如果当执行到Point A的时候已经被禁止,local_irq_enable()将产生副作用,它会重新使能中断,而不是恢复之前的中断状态。可以这样修复它: unsigned long flags; Point A: 不论Point A的中断处于什么状态,上述代码都将正确执行。 相关阅读: Fedora下内核编译 如果内核使能了抢占,仅仅禁止中断将无法确保对临界区的保护,因为另一个处于进程上下文的执行单元可能会进入临界区。重新回到图2-4,现在,除了C以外,执行单元A和B必须提防彼此。显而易见,解决该问题的方法是在进入临界区之前禁止内核抢占、中断,并在退出临界区的时候恢复内核抢占和中断。因此,执行单元A和B使用了自旋锁API的irq变体: unsigned long flags; Point A: /* ... Critical Section ... */ /* Restore interrupt state to what it was at Point A */ 我们不需要在最后显示地恢复Point A的抢占状态,因为内核自身会通过一个名叫抢占计数器的变量维护它。在抢占被禁止时(通过调用preempt_disable()),计数器值会增加;在抢占被使能时(通过调用preempt_enable()),计数器值会减少。只有在计数器值为0的时候,抢占才发挥作用。 4. 案例4:进程和中断上下文,SMP机器,抢占内核 现在假设临界区执行于SMP机器上,而且你的内核配置了CONFIG_SMP和CONFIG_PREEMPT。 到目前为止讨论的场景中,自旋锁原语发挥的作用仅限于使能和禁止抢占和中断,时间的锁功能并未被完全编译进来。在SMP机器内,锁逻辑被编译进来,而且自旋锁原语确保了SMP安全性。SMP使能的含义如下: unsigned long flags; Point A: /* ... Critical Section ... */ /* 在SMP系统上,获取自旋锁时,仅仅本CPU上的中断被禁止。因此,一个进程上下文的执行单元(图2-4中的执行单元A)在一个CPU上运行的同时,一个中断处理函数(图2-4中的执行单元C)可能运行在另一个CPU上。非本CPU上的中断处理函数必须自旋等待本CPU上的进程上下文代码退出临界区。中断上下文需要调用spin_lock()/spin_unlock(): spin_lock(&mylock); /* ... Critical Section ... */ spin_unlock(&mylock); 除了有irq变体以外,自旋锁也有底半部(BH)变体。在锁被获取的时候,spin_lock_bh()会禁止底半部,而spin_unlock_bh()则会在锁被释放时重新使能底半部。我们将在第4章讨论底半部。 -rt树 实时(-rt)树,也被称作CONFIG_PREEMPT_RT补丁集,实现了内核中一些针对低延时的修改。该补丁集可以从www.kernel.org/pub/linux/kernel/projects/rt下载,它允许内核的大部分位置可被抢占,但是用自旋锁代替了一些互斥体。它也合并了一些高精度的定时器。数个-rt功能已经被融入了主线内核。详细的文档见http://rt.wiki.kernel.org/。 为了提高性能,内核也定义了一些针对特定环境的特定的锁原语。使能适用于代码执行场景的互斥机制将使代码更高效。下面来看一下这些特定的互斥机制。 |