我对ARM平台上Linux内核中的互斥锁实现有疑问。
__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
{
int __ex_flag, __res;
__asm__ (
"ldrex %0, [%2] \n\t"
"sub %0, %0, #1 \n\t"
"strex %1, %0, [%2] " //for ARMv6+ ,kernel use ldrex/strex implement mutex lock.
: "=&r" (__res), "=&r" (__ex_flag)
: "r" (&(count)->counter)
: "cc","memory" );
__res |= __ex_flag; //How can we know the "strex" operation is successfully finished or not?
//The status of (atomic_t *count) is different in these two cases.
//I wonder this is a bug ,or I did not understand the lock mechanism so well.
if (unlikely(__res != 0))
fail_fn(count);
}
非常感谢您对此问题的建议或回答。任何事情都会受到赞赏。
有关源代码的更多信息,请参阅; http://lxr.oss.org.cn/source/arch/arm/include/asm/mutex.h?v=3.5.2;a=arm
文件路径为:
linux-3.5.2/arch/arm/include/asm/mutex.h
答案 0 :(得分:4)
__res
为零
STREX {cond} Rd,Rm,[Rn]存储到Rn中的地址,如果在Rd中成功则标记 (如果成功则Rd = 0)
请注意__res
与__ex_flag
__res |= __ex_flag;
因此,如果ldrex
或strex
操作失败,则检查失败。
注意:如果在ldrex
之后访问该值,则独占访问失败; strex
失败,并且不会存储该值。有关此内容的更多信息,请参见info center:
STREX指令执行单词的条件存储 记忆。 如果专用监视器允许存储,则操作 更新内存位置并在目标中返回值0 注册,表示操作成功。如果是独家的 监视器不允许存储,操作不更新 内存位置并在目标寄存器中返回值。
重点是,如果独占访问失败,无论是加载还是存储,内核都会知道它,因为__ex_flags=1
或__res=1
,如果它没有失败,但互斥锁已被锁定我们仍然会知道它,因为__res=0xFFFFFFFF
此时独占访问权限是否失败并不重要,因为互斥锁已锁定。
现在,我看到的唯一问题是它会将0xFFFFFFFF
存储到计数中,但是当锁定互斥锁的人解锁时,它可能会再次增加,这意味着它可能是多个线程在互斥锁上等待的方法。这来自您链接中的评论:
如果一旦递减它不为零,或者由于a而导致其存储失败 关于专卖店的争议,我们只是立即通过纾困 慢速路径锁定将被重新尝试,直到成功为止。