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


47

나는 커널 코드를 읽고 있었고, 한 곳에서 if다음과 같은 문장 내에서 표현을 보았습니다.

if (value == (SPINLOCK_SHARED | 1) - 1) {
         ............
}

SPINLOCK_SHARED = 0x80000000미리 정의 된 상수는 어디에 있습니까 ?

(SPINLOCK_SHARED | 1) - 1타입 변환 목적으로 왜 우리가 필요한지 궁금합니다 . 식의 결과는 80000000입니다. 0x80000000과 같습니다. 그렇지 않습니까? 그러나 ORing 1과 빼기 1이 중요한 이유는 무엇입니까?

내가 뭔가를 얻지 못하는 느낌이 ..


3
#define SPINLOCK_SHARED 0x80000000
RaGa__M

1
이유가없는 것 같습니다. 아마도 복사 붙여 넣기 일 것입니다. 정확하게 찾은 위치 (커널 버전, 파일 등)를 추가 할 수 있습니까?
Sander De Dycker


2
동일한 소스 코드 파일에도 포함되어 있습니다 if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1)).
Eric Postpischil

2
그런 다음 저자에게 왜 바뀌 었는지 물어봐야한다고 생각합니다.
funnydman

답변:


1

명확성을 위해 방금 완료되었습니다. 그게 전부입니다. atomic_fetchadd_int () (예 : sys / spinlock2.h)는 PRIOR 값을 더하기 / 빼기에 반환하고 해당 값은 _spin_lock_contested ()로 전달되기 때문입니다.

C 컴파일러는 모든 상수 표현식을 완전히 사전 계산합니다. 실제로 컴파일러는 프로 시저가 해당 인수에서 상수로 전달 될 때 전달 된 프로 시저 인수를 사용하는 조건에 따라 인라인 코드를 최적화 할 수도 있습니다. sys / lock.h의 lockmgr () 인라인에 case 문이 있습니다 .... 전체 case 문이 최적화되어 적절한 함수에 대한 직접 호출로 변환되기 때문입니다.

또한, 이러한 모든 잠금 기능에서 원자 작전의 오버 헤드는 다른 모든 계산보다 2 배 또는 3 배 큰 차이가 있습니다.

-매트


이 답변은 저자의 것입니다 !!!
RaGa__M

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);
}

컨테스트가없는 경우 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 | 1) - 1부분을 이해하고 value == SPINLOCK_SHARED내 생각은 우리가 ......... 독점적으로 잠금을 설정, 예 set.if 이전 값이 있는지 공유 플래그를 체크하고 있기 때문에, 너무
RaGa__M

1
@RaGa__M : if검사 의 의도는 value + 1( spin->counta그 동안 아무것도 변경되지 않은 것과 같은 값이어야 함 ) 같은지 확인하는 것 SPINLOCK_SHARED | 1입니다. if수표를로 작성하면 value == SPINLOCK_SHARED이 의도가 명확하지 않으며 수표의 의미를 파악하기가 훨씬 더 어려워집니다. 모두를 유지 SPINLOCK_SHARED | 1하고 - 1에 명시 적으로 if확인하는 것은 의도적이다.
Sander De Dycker

그러나 실제로 혼란을 야기하고 있습니다.
RaGa__M

왜 안돼 if (value + 1 == (SPINLOCK_SHARED | 1) )?
Pablo H

글쎄 .... value & SPINLOCK_SHARED더 읽기 쉬운 것일 수 있습니다 .
RaGa__M

10

나는 아마도 가장 낮은 비트를 무시하는 것이 목표라고 생각합니다.

  • 이진수로 표현 된 SPINLOCK_SHARED가 xxx0이면-> 결과는 xxx0입니다
  • SPINLOCK_SHARED = xxx1이면-> 결과도 xxx0입니다

비트 마스크 표현을 사용하는 것이 더 명확했을까요?


8
이것이 코드가하는 일이지만 문제는 가장 중요하지 않은 비트 세트가없는 정의 된 상수에 대해 그렇게 할 것입니까?
Sander De Dycker

4
@SanderDeDycker 리눅스 커널 때문에?
Lundin

9
@Lundin 리눅스 커널은 이해할 수있는 코딩 방법이 면제되지 않습니다. 정반대.
Qix-MONICA가 MISTREATED했습니다.

2
@Qix 당신이 그렇게 말한다면. 코드를 들여다보고 커널 코딩 스타일 문서를 읽을 때까지 나는 리눅스를 좋아했다. 요즘 나는 리눅스 컴퓨터와 10 미터의 안전 거리를 유지한다.
Lundin

2
@Qix Nah 소스 코드를 기준으로 판단하고 있습니다.
Lundin

4

효과

(SPINLOCK_SHARED | 1) - 1

와 비교하기 전에 결과의 하위 비트가 지워지도록하는 것입니다 value. 나는 그것이 무의미 해 보이지만 분명히 하위 순서 비트는이 코드에서 명백하지 않은 특정 사용법이나 의미를 가지고 있음에 동의하며, 우리는 개발자가 이것을해야 할 충분한 이유가 있다고 생각해야한다고 생각합니다. 흥미로운 질문은- | 1) -1보고있는 코드베이스에서 동일한 패턴 ( )이 사용됩니까?


2

비트 마스크를 작성하는 난독 화 된 방법입니다. 읽을 수있는 버전 : value == (SPINLOCK_SHARED & ~1u).


5
예, 그러나 . OP는 알려진 상수 인 경우 왜 그런지 묻습니다 SPINLOCK_SHARED. 그들이 단순히 SPINLOCK_SHARED마스크에 존재하는지 테스트하고 있다면 if (value & SPINLOCK_SHARED)어떨까요?
Qix-MONICA가 MISTREATED되었습니다.

4
value == (SPINLOCK_SHARED & ~1u)value == (SPINLOCK_SHARED | 1) - 1의 유형이보다 SPINLOCK_SHARED넓은 경우에도 작동 하므로 동등하지 않습니다 unsigned.
Eric Postpischil

4
솔직히, 나는 그것이 & ~1u더 명확 하지 않다 . 나는 & 0xFFFFFFFE내 대답에서 제안 할 생각을 했지만 실제로는 명확하지 않다는 것을 깨달았습니다. 그러나 당신의 제안은 간결함의 이점을 가지고 있습니다. :-)
Bob Jarvis-복직 모니카

6
@ 룬딘 : 우리는 그것이 될지 모른다 0x80000000. OP는로 정의 #define SPINLOCK_SHARED 0x80000000되었지만 내부에있을 수 있으며 #if…#endif다른 상황에서 다른 정의가 사용 되거나이 코드의 작성자가 정의가 편집되거나 코드가 다른 헤더로 컴파일 된 경우에도 작동하도록 의도했을 수 있습니다 다르게 정의하십시오. 어쨌든, 두 코드는 그 자체로 동등하지 않습니다.
Eric Postpischil

2
@ BobJarvis-ReinstateMonica 매일 비트 연산자를 사용하는 사람들에게는 훨씬 명확합니다. 정규 산술과 비트 단위를 혼합하는 것은 혼란 스럽습니다.
Lundin

0

이와 같은 경우는 몇 가지 추가 사례를 처리하기 위해 수행됩니다. 예를 들어이 경우에는 SPINLOCK_SHARED1이 될 수 없습니다.

int SPINLOCK_SHARED = 0x01

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

2
의미가 있지만 실제로 질문에서 명확하지는 않지만 SPINLOCK_SHARED정의 된 상수이고 테스트 된 변수는 value입니다. 이 경우에 미스터리가 남아 있습니다.
Roberto Caboni

답장을 보내 주셔서 감사합니다,하지만 난 SPINLOCK_SHARED하지 0x01로, 당신은 유지 원래 케이스에 생각 | 1) - 1SPINLOCK_SHARED 들고 때, 토 부분을 0x80000000무엇의 영향 것 | 1) - 1?
RaGa__M

내가 생각할 수있는 유일한 이유는 그들이 SPINLOCK_SHARED미래에 변화되는 것을 막고 싶어했기 때문 입니다. 그러나 전혀 명확하지 않습니다. 나는 커널 개발자들에게 편지를 써서 설명을 해주거나 표현을 재정렬하여 자체 문서화하도록 요구할 것이다.
Qix-MONICA가 MISTREATED되었습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.