详解Linux2.6内核新变化(1)
即将发布的新的稳定的内核支持更多类型的处理器,并且可靠性和可扩展性得到了提高 ,因而将推动 Linux 得到更广泛的应用。在这里我们将重点介绍一些不同程度的变化,并给出部分代码样例。Linux 内核的开发已经经历了一个漫长的过程,最初是 Linus Torvalds 于1991年发布的原始的0.1版本,这个版本中包括一个基本的调度器、IPC(进程间通信)和内存管理算法。而现在它已经是一个以往操作系统的实用的替代品,在市场上表现出了强大的竞争力。越来越多的易做图机构和IT巨头的注意力正在转向 Linux。从最小的嵌入式设备到 S/390,从手表到大型企业服务器,Linux 现在几乎可以用于所有的地方。
Linux 2.6 是 Linux 开发周期中的下一个主要版本,它包括了一些强有力的特性,这些特性旨在改进高端企业服务器的性能和支持越来越多的嵌入式设备(要了解更详细的关于 Linux 2.6 对大型的、小型的以及多处理器系统支持问题的分析,请参阅参考资料一节中到 Joseph Pranevich 的“Linux 的精彩世界”的链接)。
本文为关注 Linux 的用户分析了 Linux 2.6 的一些重要特性,并且讨论了驱动程序开发人员可能会感兴趣的多方面的变化。
Linux 2.6亮点
无论是对于企业服务器还是对于嵌入式系统,Linux 2.6 都是一个巨大的进步。对高端的机器来说,新特性针对的是性能改进、可扩展性、吞吐率,以及对 SMP 机器 NUMA 的支持。对于嵌入式领域,添加了新的体系结构和处理器类型——包括对那些没有硬件控制的内存管理方案的 MMU-less 系统的支持。并且,和往常一样,为了满足桌面用户群的需要,添加了一整套新的音频和多媒体驱动程序。
在本文中,我们分析了 Linux 2.6的一些最引人关注的特性,但是仍有很多值得关注的变化,包括增强的内核核心转储、快速互斥支持、改进的I/O子系统,等等,在这里我们不能全部讨论。在侧栏中总结了其中一些,其余的我们在参考资料一节中给出了链接。
新的调度器
2.6版本的 Linux 内核使用了由 Ingo Molnar 开发的新的调度器算法,称为O(1)算法,它在高负载的情况下执行得极其出色,并且当有很多处理器时也可以很好地扩展。
在2.4版本的调度器中,时间片重算算法要求在所有的进程都用尽它们的时间片以后,它们的新时间片才会被重新计算。这样的话在一个有很多处理器的系统中,当进程用完它们的时间片以后得等待重算(以得到新的时间片),从而导致大部分的处理器处于空闲状态;这将影响SMP的效率。除此之外,当空闲的处理器开始执行那些时间片尚未用尽的处于等待状态的进程(如果它们自己的处理器忙),会导致进程开始在处理器之间“跳跃”。当一个高优先级进程或者交互式进程发生跳跃时,整个系统的性能就会受到影响。
新的调度器解决上述问题的方法是,基于每个 CPU 来分布时间片,并且取消了全局同步和重算循环。调度器使用了两个优先级数组,即活动数组和过期数组,可以通过指针来访问它们。活动数组中包含了所有映射到某个CPU而且时间片尚未用尽的任务。过期数组中包含了一个时间片已经用尽的所有任务的有序列表。如果所有活动任务的时间片都已用尽,那么指向这两个数组的指针互换,过期数组(包含了准备运行的任务)成为活动数组,而空的活动数组成为包含过期任务的新数组。数组的索引存储在一个64位的位图中,找到最高优先级的任务是很容易的。
新的调度器现在不再有大的 runqueue_lock。它维持每个处理器的运行队列/锁机制,以使得两个不同处理器上的两个进程可以完全并行地休眠、唤醒和上下文切换。重算循环(为进程重新计算时间片)和 goodness 循环已经被取消,O(1)算法用于 wakeup() 和 schedulee()。
新调度器的主要好处包括:
SMP效率:如果有工作需要完成,那么所有处理器都会工作。
等待进程:没有进程需要长时间地等待处理器;同时,没有进程会无端地占用大量的CPU时间。
SMP进程映射:进程只映射到一个CPU而且不会在CPU之间跳跃。
优先级:不重要的任务的优先级低(反之亦然)。
负载平衡:调度器会降低那些超出处理器负载能力的进程的优先级。
交互性能:使用新的调度器,即便是在非常高负载的情况下,系统花费很长时间来响应鼠标点击或者键盘输入的情况将不会再发生。
内核抢占
内核抢占补丁在2.5系列中就已经被打上,接下来在2.6中也会打。这将显著地降低用户交互式应用程序、多媒体应用程序等类似应用程序的延迟。这一特性对实时系统和嵌入式系统来说特别有用。
2.5的内核抢占模块的工作由 Robert Love 完成。在先前的内核版本中(包括2.4内核),不允许抢占以内核模式运行的任务(包括通过系统调用进入内核模式的用户任务),直到它们自己主动释放 CPU。
在内核2.6中,内核是可抢占的。一个内核任务可以被抢占,为的是让重要的用户应用程序可以继续运行。这样做最主要的优势在于,可以极大地增强系统的用户交互性,用户将会觉得鼠标点击和击键的事件得到了更快速的响应。
当然,不是所有的内核代码段都可以被抢占。可以锁定内核代码的关键部分,不允许抢占。锁定可以确保每个 CPU 的数据结构和状态始终受到保护而不被抢占。
以下的代码片断显示了每个 CPU 的数据结构问题(在SMP系统中):
清单 1. 存在内核抢占问题的代码
int arr[NR_CPUS];arr[smp_processor_id()] = i;
/* kernel preemption could happen here */
j = arr[smp_processor_id()]
/* i and j are not equal as
smp_processor_id() may not be the same */
在这种情形下,如果在特定点发生了内核抢占,任务将会由于重新调度而被分配到其他处理器——smp_processor_id() 将返回一个不同的值。
这种情形应该通过锁定来进行保护。
FPU 模式是另外一种CPU应该被保护起来不被抢占的情形。当内核在执行浮点指令时,FPU 状态不被保存。如果这时发生了抢占,由于重新调度,FPU 状态就会与抢占前完全不同。所以 FPU 代码必须始终被锁定,以防止内核抢占。
锁定可以这样来实现,在关键部分禁止抢占,在之后再激活抢占。以下是在2.6内核中禁止和激活抢占的定义:
preempt_enable() -- 抢占计数器减1
preempt_disable() -- 抢占计数器加1
get_cpu() -- 先后调用 preempt_disable() 和 smp_processor_id()
put_cpu() -- 重新激活preemption()
使用这些定义,清单 1可以重写成这样:
清单 2. 使用防抢占锁的代码
int cpu, arr[NR_CPUS];arr[get_cpu()] = i;
/* disable preemption */
j = arr[smp_processor_id()];
/* do some critical stuff here */
put_cpu()
/* re-enable preemption */
注意 preempt_disable()/enable()调用是可以嵌套的。也就是说,preempt_disable() 可以被调用 n 次,只有当第 n 次 preempt_enable() 被调用后,抢占才被重新激活。
当使用自旋锁时,抢占是被隐式地禁止的。例如,一个 spin_lock_irqsave() 调用会隐式地通过调用 preempt_disable() 来防止抢占;spin_unlock_irqrestroe() 通过调用 preempt_enable() 来重新激活抢占。
改进的线程模型以及对 NPTL 的支持
在2.5内核中已经做了很多的改进线程性能的工作。在2.6中改进的线程模型仍然是由 Ingo Molnar 来完成的。它基于一个1:1的线程模型(一个内核线程对应一个用户线程),包括内核内在的对新的 NPTL(Native Posix Threading Library)的支持,这个新的 NPTL 是由 Molnar 和 Ulrich Drepper 合作开发的。
2.6内核中其他引人注目的变化
文件系统
对 ext2/ext3 文件系统做了改进,包括对扩展属性和POSIX访问控制列表的支持。NTFS的驱动程序也已经重写,可以支持(reentrant safe)SMP,大于4KB的簇,等等。同时2.6也支持 IBM 的 JFS(journaling file system) 和 SGI 的 XFS。
音频
对桌面用户而言,一个更令人期待的特性是称为 ALSA(Advanced Linux Sound Architecture)
的新的 Linux 音频体系结构,它取代了缺陷很多的旧的 OSS (Open Sound System)。新的声音体系结构支持USB音频和MIDI设备,全双工重放,等等。在桌面上播放 MP3 和其他音频文件再也不会像以前那样了!
总线
SCSI/IDE子系统经过大幅度的重写,一些驱动程序仍然处于测试阶段或者收尾阶段。
电源管理
支持 ACPI(高级电源配置管理界面,Advanced Configuration and Power Inte易做图ce),用于调整 CPU(可以在不同的负载下使CPU工作于不同的时钟频率以节电)和软件挂起(这一特性仍在测试中)。
联网和IPSec
内核中加入了对 IPSec (IP安全)的支持,因此也支持 IP 有效负载压缩等各种 RFC。删除了原来内核内置的HTTP服务器 kttpd。IPSec 特性使用了内核提供的新的加密 API。这个加密API中包含了各种流行的算法,比如 MD4,MD5 DES,等等。加入了对新的 NFSv4 (网络文件系统)客户机/服务器的支持。
用户界面层
<