[c] (x | y)-y 왜 단순히 x 또는`x | 0

나는 커널 코드를 읽고 있었고, 한 곳에서 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_SHARED1이 될 수 없습니다.

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0


답변