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