Linux 版 (精华区)

发信人: tcpip (偶的昵称改了), 信区: Linux
标  题: 内核空间SMP编程
发信站: 紫 丁 香 (Sun Jan  9 22:06:13 2000) WWW-POST

内核空间SMP编程 

                          作者:Dave Jones 编译:杨继张

                     

        多处理机系统正在变得越来越普通。尽管大多数用户空间代码仍将完美地运行,
而且
    有些情况下不需要增加额外的代码就能利用SMP特性的优势,但是内核空间代码必须
编写成
    具备“SMP意识”且是“SMP安全的”。以下几段文字解释如何去做。

    问题

        当有多个CPU时,同样的代码可能同时在两个或多个CPU上执行。这在如下所示用
于初
    始化某个图像设备的例程中可能会出问题。
            void init_hardware(void)
            {
                outb(0x1, hardware_base + 0x30);
                outb(0x2, hardware_base + 0x30);
                outb(0x3, hardware_base + 0x30);
                outb(0x4, hardware_base + 0x30);
            }
        假设该硬件依赖于寄存器0x30按顺序依次被设为0、1、2、3来初始化,那么要是
有另
    一个CPU来参乎的话,事情就会搞糟。想象有两个CPU的情形,它们都在执行这个例程
,不
    过2号CPU进入得稍慢点:
            CPU 1                           CPU 2

            0x30 = 1
            0x30 = 2                        0x30 = 1
            0x30 = 3                        0x30 = 2
            0x30 = 4                        0x30 = 3
                                            0x30 = 4
        这会发生什么情况呢?从我们设想的硬件设备看来,它在寄存器0x30上收到的字
节按
    顺序为:1、2、1、3、2、4、3、4。
        啊!原本好好的事第二个CPU一来就搞得一团糟了也。所幸的是,我们有防止这
类事情
    发生的办法。

    自旋锁小历史

        2.0.x版本的Linux内核通过给整个内核引入一个全局变量来防止多于一个CPU会
造成的
    问题。这意味着任何时刻只有一个CPU能够执行来自内核空间的代码。这样尽管能工
作,但
    是当系统开始以多于2个的CPU出现时,扩展性能就不怎么好。
        2.1.x版本的内核系列加入了粒度更细的SMP支持。这意味着不再依赖于以前作为
全局
    变量出现的“大锁”,而是每个没有SMP意识的例程现在都需要各自的自旋锁。文件
asm/
    spinlock.h中定义了若干类型的自旋锁。
        有了局部化的自旋锁后,不止一个CPU同时执行内核空间代码就变得可能了。

    简单的自旋锁

        理解自旋锁的最简单方法是把它作为一个变量看待,该变量把一个例程或者标记

    “我当前在另一个CPU上运行,请稍等一会”,或者标记为“我当前不在运行”。如
果1号
    CPU首先进入该例程,它就获取该自旋锁。当2号CPU试图进入同一个例程时,该自旋
锁告诉
    它自己已为1号CPU所持有,需等到1号CPU释放自己后才能进入。
            spinlock_t my_spinlock = SPIN_LOCK_UNLOCKED;
            unsigned long flags;

            spin_lock (&my_spinlock);
            ...
            critical section
            ...
            spin_unlock (&my_spinlock);
            
    中断

        设想我们的硬件的驱动程序还有一个中断处理程序。该处理程序需要修改某些由
我们
    的驱动程序定义的全局变量。这会造成混乱。我们如何解决呢?
        保护某个数据结构,使它免遭中断之修改的最初方法是全局地禁止中断。在已知
只有
    自己的中断才会修改自己的驱动程序变量时,这么做效率很低。所幸的是,我们现在
有更
    好的办法了。我们只是在使用共享变量期间禁止中断,此后重新使能。
        实现这种办法的函数有三个:
            disable_irq()
            enable_irq()
            disable_irq_nosync()
        这三个函数都取一个中断号作为参数。注意,禁止一个中断的时间太长会导致难
以追
    踪程序缺陷,丢失数据,甚至更坏。
        disable_irq函数的非同步版本允许所指定的IRQ处理程序继续运行,前提是它已
经在
    运行,普通的disable_irq则所指定的IRQ处理程序不在如何CPU上运行。
        如果需要在中断处理程序中修改自旋锁,那就不能使用普通的spin_lock()和
    spin_unlock(),而应该保存中断状态。这可通过给这两个函数添加_irqsave后缀很
容易地
    做到:
            spinlock_t my_spinlock = SPIN_LOCK_UNLOCKED;
            unsigned long flags;

            spin_lock_irqsave(&my_spinlock, flags);
            ...
            critical section
            ...
            spin_unlock_irqrestore (&my_spinlock, flags);

    ――Dave Jones,1999年11月30日


--
"这一千多年没写诗了?"
"写了, 不过只写了两句."
"千年得两句, 一定是万古丽句了. 念来听听."
"好吧, 我现丑了" 太白星清了清嗓子, 浑厚的男中音在天庭响起:
大海啊, 都是水;
骏马啊, 四条腿;

※ 来源:·紫 丁 香 bbs.hit.edu.cn·[FROM: tcpip.hit.edu.c] 
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.758毫秒