나는 커널 코드를 읽고 있었고, 한 곳에서 if
다음과 같은 문장 내에서 표현을 보았습니다.
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
SPINLOCK_SHARED = 0x80000000
미리 정의 된 상수는 어디에 있습니까 ?
(SPINLOCK_SHARED | 1) - 1
타입 변환 목적으로 왜 우리가 필요한지 궁금합니다 . 식의 결과는 80000000입니다. 0x80000000과 같습니다. 그렇지 않습니까? 그러나 ORing 1과 빼기 1이 중요한 이유는 무엇입니까?
내가 뭔가를 얻지 못하는 느낌이 ..
답변
명확성을 위해 방금 완료되었습니다. 그게 전부입니다. atomic_fetchadd_int () (예 : sys / spinlock2.h)는 PRIOR 값을 더하기 / 빼기에 반환하고 해당 값은 _spin_lock_contested ()로 전달되기 때문입니다.
C 컴파일러는 모든 상수 표현식을 완전히 사전 계산합니다. 실제로 컴파일러는 프로 시저가 해당 인수에서 상수로 전달 될 때 전달 된 프로 시저 인수를 사용하는 조건에 따라 인라인 코드를 최적화 할 수도 있습니다. sys / lock.h의 lockmgr () 인라인에 case 문이 있습니다 …. 전체 case 문이 최적화되어 적절한 함수에 대한 직접 호출로 변환되기 때문입니다.
또한, 이러한 모든 잠금 기능에서 원자 작전의 오버 헤드는 다른 모든 계산보다 2 배 또는 3 배 큰 차이가 있습니다.
-매트
답변
다른 사람이 잠금을 얻으려고 할 때 _spin_lock_contested
호출되는 코드는 _spin_lock_quick
에 있습니다.
count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
_spin_lock_contested(spin, ident, count);
}
컨테스트가없는 경우 count
(이전 값)은이어야 0
하지만 그렇지 않습니다. 이 count
값을 매개 변수로 전달 _spin_lock_contested
은 AS value
매개 변수입니다. 이것은 value
다음과 체크 if
영업에서 :
/*
* 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;
}
명심 value
의 이전 값 spin->counta
, 후자는 이미 1 씩 증가하고있다, 우리는 기대 spin->counta
동일하게 value + 1
(뭔가 그 동안 변경하지 않는 한).
따라서 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
, 그것은 비교의 의미를 명확히하기 위해, 그대로 남아있는 (예. 테스트 값으로 증가 이전 값을 비교).
아니면 야 대답은 명확하고 코드 일관성을 유지하는 것으로 보입니다.
답변
나는 아마도 가장 낮은 비트를 무시하는 것이 목표라고 생각합니다.
- 이진수로 표현 된 SPINLOCK_SHARED가 xxx0이면-> 결과는 xxx0입니다
- SPINLOCK_SHARED = xxx1이면-> 결과도 xxx0입니다
비트 마스크 표현을 사용하는 것이 더 명확했을까요?
답변
효과
(SPINLOCK_SHARED | 1) - 1
와 비교하기 전에 결과의 하위 비트가 지워지도록하는 것입니다 value
. 나는 그것이 무의미 해 보이지만 분명히 하위 순서 비트는이 코드에서 명백하지 않은 특정 사용법이나 의미를 가지고 있음에 동의하며, 우리는 개발자가 이것을해야 할 충분한 이유가 있다고 생각해야한다고 생각합니다. 흥미로운 질문은- | 1) -1
보고있는 코드베이스에서 동일한 패턴 ( )이 사용됩니까?
답변
비트 마스크를 작성하는 난독 화 된 방법입니다. 읽을 수있는 버전 : value == (SPINLOCK_SHARED & ~1u)
.
답변
이와 같은 경우는 몇 가지 추가 사례를 처리하기 위해 수행됩니다. 예를 들어이 경우에는 SPINLOCK_SHARED
1이 될 수 없습니다.
int SPINLOCK_SHARED = 0x01
int res = (SPINLOCK_SHARED | 1) - 1 // 0