cli()/sti()移除指南

cli()/sti()移除指南

UniProcessor:UP 单处理器
MultiProcessor:MP 多处理器
#### cli()/sti() removal guide, started by Ingo Molnar [email protected]

[原文:linux-2.6.22/Documentation/cli-sti-removal.txt]
CN Translated by [email protected]
Version 1.0

as of 2.5.28, five popular macros have been removed on SMP, and are being phased out on UP:
cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags), until now it was possible to protect driver code against interrupt handlers via a cli(), but from now on other, more lightweight methods have to be used for synchronization, such as spinlocks or semaphores.
针对2.5.28内核,五个常用的宏在SMP系统上已经被删除,在UP系统上也正逐渐删除:cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags)在这以前,主要通过cli()保护驱动代码不受中断处理程序的干扰,现在有更轻量级的方法用作同步如自旋锁,信号量。

for example, driver code that used to do something like:
例如,如下的驱动代码在SMP系统上是正确的:

    struct driver_data;

    irq_handler (...)
    {
        ....
        driver_data.finish = 1;
        driver_data.new_work = 0;
        ....
    }

    ...

    ioctl_func (...)
    {
        ...
        cli();
        ...
        driver_data.finish = 0;
        driver_data.new_work = 2;
        ...
        sti();
        ...
    }

was SMP-correct because the cli() function ensured that no interrupt handler (amongst them the above irq_handler()) function would execute while the cli()-ed section is executing.
因为cli()函数保证当cli()-ed的区域在执行的时候,没有一个中断处理函数可以执行。

but from now on a more direct method of locking has to be used:
但是从现在开始,可以使用一种更直接的锁。

    spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
    struct driver_data;

    irq_handler (...)
    {
        unsigned long flags;
        ....
        spin_lock_irqsave(&driver_lock, flags);
        ....
        driver_data.finish = 1;
        driver_data.new_work = 0;
        ....
        spin_unlock_irqrestore(&driver_lock, flags);
        ....
    }

    ...

    ioctl_func (...)
    {
        ...
        spin_lock_irq(&driver_lock);
        ...
        driver_data.finish = 0;
        driver_data.new_work = 2;
        ...
        spin_unlock_irq(&driver_lock);
        ...
    }

the above code has a number of advantages:

- the locking relation is easier to understand - actual lock usage
  pinpoints the critical sections. cli() usage is too opaque.
  Easier to understand means it's easier to debug.

- it's faster, because spinlocks are faster to acquire than the
  potentially heavily-used IRQ lock. Furthermore, your driver does
  not have to wait eg. for a big heavy SCSI interrupt to finish,
  because the driver_lock spinlock is only used by your driver.
  cli() on the other hand was used by many drivers, and extended
  the critical section to the whole IRQ handler function - creating
  serious lock contention.
上面的代码有许多好处:
-容易理解锁的关系-锁的使用突出了临界区域。cli()的使用显得比较难懂。容易理解意味着方便调试。

-速度较快,因为获得自旋锁比大量使用的IRQ锁要快。而且驱动代码没有必要等待中断结束(如一个耗时的SCSI中断),因为只有你的驱动使用driver_lock自旋锁。另一方面很多驱动都会使用cli(),使得临界区域扩展到整个IRQ中断处理函数-这样就创建了严重的锁竞争。
to make the transition easier, we've still kept the cli(), sti(), save_flags(), save_flags_cli() and restore_flags() macros defined on UP systems - but their usage will be phased out until 2.6 is
released.
为了方便过渡,仍然在UP系统上保留了宏定义cli(), sti(), save_flags(), save_flags_cli() and restore_flags(),但是2.6 的release会删除它们的使用。

drivers that want to disable local interrupts (interrupts on the current CPU), can use the following five macros:
驱动如果想禁止本地中断(在当前CPU上的中断),可以使用下面的五个宏:

  local_irq_disable(), local_irq_enable(), local_save_flags(flags), local_irq_save(flags), local_irq_restore(flags)

but beware, their meaning and semantics are much simpler, far from that of the old cli(), sti(), save_flags(flags) and restore_flags(flags) SMP meaning:
同旧的宏cli(), sti(), save_flags(flags) and restore_flags(flags)相比,它们的意义和语义相对简单,

    local_irq_disable()       => turn local IRQs off

    local_irq_enable()        => turn local IRQs on

    local_save_flags(flags)   => save the current IRQ state into flags. The
                                 state can be on or off. (on some
                                 architectures there's even more bits in it.)

    local_irq_save(flags)     => save the current IRQ state into flags and
                                 disable interrupts.

    local_irq_restore(flags)  => restore the IRQ state from flags.

(local_irq_save can save both irqs on and irqs off state, and local_irq_restore can restore into both irqs on and irqs off state.)

another related change is that synchronize_irq() now takes a parameter: synchronize_irq(irq). This change too has the purpose of making SMP synchronization more lightweight - this way you can wait for your own interrupt handler to finish, no need to wait for other IRQ sources.
另外一个相关的变化是函数synchronize_irq()现在需要一个参数:synchronize_irq(irq)。这个变化的目的使得SMP同步更快了-通过这种方式,就可以只等待自己的中断处理函数,没有必要等待其他的IRQ资源。

why were these changes done? The main reason was the architectural burden of maintaining the cli()/sti() interface - it became a real problem. The new interrupt system is much more streamlined, easier to understand, debug, and it's also a bit faster - the same happened to it that will happen to cli()/sti() using drivers once they convert to spinlocks :-)
为什么做这些变化?主要的原因是维护接口cli()/sti()对应的系统架构负担-成为了一个真正的问题。新的中断系统更加流水线化,容易理解,调试,也更快了-一旦驱动代码由cli()/sti()转换成自旋锁,也会发生同样的事情:-)。

 

 

摘自:http://wg206.spaces.live.com/blog/cns!F96F35563934F232!569.entry

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章