首页 | Linux 基础 | 资讯动态 | Linux 应用 | Linux 服务器 | Linux 开发 | Linux 安全 | 专题 | 联盟论坛
  当前位置:主页>Linux 开发>文章内容
内核空间SMP编程
来源:www.unix5.com 作者:riechelr_hl 发布时间:2007-05-22  

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


 
如果您对本文有任何疑问或者建议,请到论坛讨论区发表您的意见: >> 论坛入口
[收藏] [推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
  热点文章
·嵌入式Linux系统下图形库讲解及
·Qt/Embedded在嵌入式Linux中的应
·Linux系统环境下的Socket编程详
·在 Fedora Core 5 上体验 Aiglx
·使用 Linux 系统调用的内核命令
·Linux 2.6.11内核文件IO系统调用
·在Linux中创建静态库和动态库
·嵌入式Linux:uClinux操作系统移
·Linux操作系统下的多进程编程(
·嵌入式系统 Boot Loader 技术内
·Linux操作系统的源代码目录树结
·Linux用户态与内核态的交互讲解
  相关文章
·剖析RedHat Linux中三个重要内核
·Linux 防火墙在内核中的实现
·细看嵌入式Linux时代发展
·介绍B-SHELL的一些运用方法
·Linux程式设计.Shell Script(bas
·Linux系统单一内核模块编译过程
·Linux程式设计.Shell Script(bas
·Linux程式设计.Shell Script(bas
·嵌入式Linux系统的GDB远程调试的
·关于嵌入式Linux系统进程调度的
·教你一种实现嵌入式Linux系统新
·剖析Linux 2.6内核在嵌入式上的

本站信息源至:互联网络,均为学习,交流所用,如有版权问题,请联系我们.
站长QQ:397422079 E_mail:riechelr_hl@unix5.com
转载本站内容请注明原作者名.谢谢!