RaG*_*__M 47 c bit-manipulation
我正在阅读内核代码,并且在一个地方我看到了if语句中的一个表达式,例如
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
Run Code Online (Sandbox Code Playgroud)
其中SPINLOCK_SHARED = 0x80000000是预定义的常量。
我想知道为什么我们需要(SPINLOCK_SHARED | 1) - 1- 用于类型转换目的?表达式的结果将是 80000000-- 与 0x80000000 相同,不是吗?然而,为什么 ORing 1 和 Subtracting 1 很重要?
有一种感觉,我想得到一些东西..
San*_*ker 31
代码位于 中_spin_lock_contested,_spin_lock_quick当其他人试图获取锁时调用该代码:
count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
_spin_lock_contested(spin, ident, count);
}
Run Code Online (Sandbox Code Playgroud)
如果没有比赛,那么count(之前的值)应该是0,但它不是。该count值作为参数传递给_spin_lock_contested作为value参数。这value然后与检查if从OP:
/*
* WARNING! Caller has already incremented the lock. We must
* increment the count value (from the inline's fetch-add)
* to match.
*
* Handle the degenerate case where the spinlock is flagged SHARED
* with only our reference. We can convert it to EXCLUSIVE.
*/
if (value == (SPINLOCK_SHARED | 1) - 1) {
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
return;
}
Run Code Online (Sandbox Code Playgroud)
请记住,这value是 的先前值spin->counta,而后者已经增加了 1,我们期望spin->counta相等value + 1(除非在此期间发生了某些变化)。
因此,检查 if spin->counta == SPINLOCK_SHARED | 1( 的前提atomic_cmpset_int)对应于检查 if value + 1 == SPINLOCK_SHARED | 1,它可以重写为value == (SPINLOCK_SHARED | 1) - 1(同样,如果在此期间没有任何变化)。
虽然value == (SPINLOCK_SHARED | 1) - 1可以重写为value == SPINLOCK_SHARED,但它保持原样,以阐明比较的意图(即将增加的先前值与测试值进行比较)。
或者哦。答案似乎是:为了清晰和代码一致性。
Gui*_*ean 10
我认为目标可能是忽略最低有效位:
使用位掩码表达式也许会更清楚?
小智 1
只是为了清楚起见才这样做的,仅此而已。这是因为atomic_fetchadd_int()(例如sys/spinlock2.h)返回加法/减法之前的值,并且该值被传递给_spin_lock_contested()
请注意,C 编译器完全预先计算所有常量表达式。事实上,当过程在这些参数中传递常量时,编译器甚至可以根据使用传入过程参数的条件优化内联代码。这就是为什么 sys/lock.h 中的 lockmgr() 内联有一个 case 语句......因为整个 case 语句将被优化并转变成对适当函数的直接调用。
此外,在所有这些锁定函数中,原子操作的开销使所有其他计算相形见绌两个或三个数量级。
-马特