持有自旋锁自动返回是不安全的吗?
Is returning while holding a spinlock automatically unsafe?
The flags
argument passed to spin_unlock_irqrestore
must be the same variable passed to spin_lock_irqsave
. You must also call spin_lock_irqsave
and spin_unlock_irqrestore
in the same function; otherwise your code may break on some architectures.
但我找不到 the official documentation bundled with the kernel code itself. And I find driver code that violates this guidance 要求的任何此类限制。
显然,从不同的函数调用 spin_lock_irqsave
和 spin_unlock_irqrestore
不是一个好主意,因为你应该尽量减少持有锁时所做的工作(禁用中断,不较少的!)。但是如果小心地对内核进行更改是否可以实现,它实际上从未违反 API 合同,还是仍然禁止这样做?
如果限制在某个时候被移除,它是否适用于版本 3.10.17?
除了这本书,我从未见过这种限制。可能,书中给出的信息已经过时,或者..完全错误。
在当前内核中(至少从我开始使用的 2.6.32 开始)实际锁定是通过来自 spin_lock_irqsave
的多级嵌套调用完成的(参见,例如 __raw_spin_lock_irqsave ,在中间调用)。因此 lock
和 unlock
的不同功能上下文可能很难成为功能失调的原因。
这只是一个猜测,但可能不清楚是指一个潜在的错误,如果您尝试使用 非本地 变量或 [=34= 的存储位置,可能会发生该错误]标志.
基本上,flags 必须是当前执行上下文私有的,这就是为什么 spin_lock_irqsave
是一个采用 flags
名称的宏的原因.在保存 flags 时,您还没有自旋锁。
这与不同功能中的锁定和解锁有何关系:
考虑一些驱动程序开发人员可能编写的两个函数:
void my_lock(my_object *ctx)
{
spin_lock_irqsave(&ctx->mylock, ctx->myflags); /* BUG */
}
void my_unlock(my_object *ctx)
{
spin_unlock_irqrestore(&ctx->mylock, ctx->myflags);
}
这是一个错误,因为在写入 ctx->myflags
时,锁尚未持有,它是一个对其他上下文和处理器可见的共享变量。本地标志必须保存到堆栈上的私有位置。然后,当调用者拥有锁时,可以将标志的副本保存到独占对象中。也就是说,可以这样固定:
void my_lock(my_object *ctx)
{
unsigned long flags;
spin_lock_irqsave(&ctx->mylock, flag);
ctx->myflags = flags;
}
void my_unlock(my_object *ctx)
{
unsigned long flags = ctx->myflags; /* probably unnecessary */
spin_unlock_irqrestore(&ctx->mylock, flags);
}
如果不能像那样修复它,将很难实现需要包装 IRQ 自旋锁的更高级别的原语。
它如何依赖于 arch:
假设spin_lock_irqsave
扩展为机器码,将当前标志保存在某个寄存器中,然后获得锁,然后 将该寄存器保存到指定的 flags
目的地。在那种情况下,错误代码实际上是安全的。如果扩展代码将标志保存到调用者指定的实际 flags
对象中,然后尝试获取锁,那么它就被破坏了。
The
flags
argument passed tospin_unlock_irqrestore
must be the same variable passed tospin_lock_irqsave
. You must also callspin_lock_irqsave
andspin_unlock_irqrestore
in the same function; otherwise your code may break on some architectures.
但我找不到 the official documentation bundled with the kernel code itself. And I find driver code that violates this guidance 要求的任何此类限制。
显然,从不同的函数调用 spin_lock_irqsave
和 spin_unlock_irqrestore
不是一个好主意,因为你应该尽量减少持有锁时所做的工作(禁用中断,不较少的!)。但是如果小心地对内核进行更改是否可以实现,它实际上从未违反 API 合同,还是仍然禁止这样做?
如果限制在某个时候被移除,它是否适用于版本 3.10.17?
除了这本书,我从未见过这种限制。可能,书中给出的信息已经过时,或者..完全错误。
在当前内核中(至少从我开始使用的 2.6.32 开始)实际锁定是通过来自 spin_lock_irqsave
的多级嵌套调用完成的(参见,例如 __raw_spin_lock_irqsave ,在中间调用)。因此 lock
和 unlock
的不同功能上下文可能很难成为功能失调的原因。
这只是一个猜测,但可能不清楚是指一个潜在的错误,如果您尝试使用 非本地 变量或 [=34= 的存储位置,可能会发生该错误]标志.
基本上,flags 必须是当前执行上下文私有的,这就是为什么 spin_lock_irqsave
是一个采用 flags
名称的宏的原因.在保存 flags 时,您还没有自旋锁。
这与不同功能中的锁定和解锁有何关系:
考虑一些驱动程序开发人员可能编写的两个函数:
void my_lock(my_object *ctx)
{
spin_lock_irqsave(&ctx->mylock, ctx->myflags); /* BUG */
}
void my_unlock(my_object *ctx)
{
spin_unlock_irqrestore(&ctx->mylock, ctx->myflags);
}
这是一个错误,因为在写入 ctx->myflags
时,锁尚未持有,它是一个对其他上下文和处理器可见的共享变量。本地标志必须保存到堆栈上的私有位置。然后,当调用者拥有锁时,可以将标志的副本保存到独占对象中。也就是说,可以这样固定:
void my_lock(my_object *ctx)
{
unsigned long flags;
spin_lock_irqsave(&ctx->mylock, flag);
ctx->myflags = flags;
}
void my_unlock(my_object *ctx)
{
unsigned long flags = ctx->myflags; /* probably unnecessary */
spin_unlock_irqrestore(&ctx->mylock, flags);
}
如果不能像那样修复它,将很难实现需要包装 IRQ 自旋锁的更高级别的原语。
它如何依赖于 arch:
假设spin_lock_irqsave
扩展为机器码,将当前标志保存在某个寄存器中,然后获得锁,然后 将该寄存器保存到指定的 flags
目的地。在那种情况下,错误代码实际上是安全的。如果扩展代码将标志保存到调用者指定的实际 flags
对象中,然后尝试获取锁,那么它就被破坏了。