C 프로그래머들은 종종 현재 실행 스레드 외부에서 변수가 변경 될 수 있음을 의미하기 위해 일시적으로 변합니다. 결과적으로 공유 데이터 구조를 사용할 때 커널 코드에서 사용하려고하는 경우가 있습니다. 다시 말해, 그들은 휘발성 유형을 일종의 쉬운 원자 변수로 취급하는 것으로 알려져 있습니다. 커널 코드에서 휘발성을 사용하는 것은 거의 정확하지 않습니다. 이 문서는 이유를 설명합니다.
휘발성과 관련하여 이해해야 할 핵심은 그 목적이 최적화를 억제하는 것인데, 이는 실제로는 절대로 원하지 않는 것입니다. 커널에서, 원치 않는 동시 액세스로부터 공유 데이터 구조를 보호해야합니다. 이는 매우 다른 작업입니다. 원치 않는 동시성을 방지하는 프로세스는 거의 모든 최적화 관련 문제를보다 효율적으로 피할 수 있습니다.
휘발성과 마찬가지로 데이터에 동시에 액세스 할 수있는 커널 프리미티브 (스핀 록, 뮤텍스, 메모리 장벽 등)는 원하지 않는 최적화를 방지하도록 설계되었습니다. 그것들이 올바르게 사용된다면, 휘발성도 사용할 필요가 없습니다. 휘발성이 여전히 필요한 경우 코드에 버그가있을 수 있습니다. 올바르게 작성된 커널 코드에서 휘발성은 작업 속도를 늦추는 역할 만 할 수 있습니다.
일반적인 커널 코드 블록을 고려하십시오.
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
모든 코드가 잠금 규칙을 따르는 경우 the_lock이 유지되는 동안 shared_data의 값이 예기치 않게 변경 될 수 없습니다. 해당 데이터로 재생하려는 다른 코드는 잠금 대기 중입니다. spinlock 프리미티브는 메모리 배리어 역할을합니다. 명시 적으로 작성되었으므로 데이터 액세스가 최적화되지 않습니다. 따라서 컴파일러는 shared_data에 무엇이 있는지 알고 있다고 생각할 수 있지만 spin_lock () 호출은 메모리 장벽으로 작동하므로 알고있는 것을 잊게합니다. 해당 데이터에 액세스 할 때 최적화 문제가 없습니다.
shared_data가 휘발성으로 선언 된 경우 여전히 잠금이 필요합니다. 그러나 컴파일러가 다른 사람과 함께 작업 할 수 없다는 것을 알고 있으면 중요한 섹션 내 에서 shared_data에 대한 액세스를 최적화하지 못하게됩니다 . 잠금이 유지되는 동안 shared_data는 휘발성이 아닙니다. 공유 데이터를 처리 할 때 적절한 잠금은 불필요하고 잠재적으로 유해합니다.
휘발성 스토리지 클래스는 원래 메모리 매핑 된 I / O 레지스터를위한 것입니다. 커널 내에서 레지스터 액세스도 잠금으로 보호해야하지만 컴파일러는 중요한 섹션 내에서 레지스터 액세스를 "최적화"하기를 원하지 않습니다. 그러나 커널 내에서 I / O 메모리 액세스는 항상 접근 자 기능을 통해 수행됩니다. 포인터를 통해 I / O 메모리에 직접 액세스하는 것은 어리둥절하며 모든 아키텍처에서 작동하지는 않습니다. 이러한 접근자는 원치 않는 최적화를 방지하기 위해 작성되므로 휘발성은 다시 한 번 불필요합니다.
휘발성을 사용하려는 유혹을받는 또 다른 상황은 프로세서가 변수 값을 기다리는 중입니다. 바쁜 대기를 수행하는 올바른 방법은 다음과 같습니다.
while (my_variable != what_i_want)
cpu_relax();
cpu_relax () 호출은 CPU 전력 소비를 낮추거나 하이퍼 스레드 트윈 프로세서에 대한 수율을 제공합니다. 또한 메모리 장벽 역할을하기 때문에 다시 한번 휘발성이 필요하지 않습니다. 물론, 바쁘게 기다리는 것은 일반적으로 시작하는 반 사회적 행동입니다.
커널에서 휘발성이 의미가있는 몇 가지 드문 상황이 여전히 있습니다.
위에서 언급 한 접근 자 함수는 직접 I / O 메모리 액세스가 작동하는 아키텍처에서 휘발성을 사용할 수 있습니다. 기본적으로 각 접근 자 호출은 자체적으로 약간 중요한 부분이되고 프로그래머가 예상 한대로 액세스가 이루어 지도록합니다.
메모리를 변경하지만 다른 눈에 띄는 부작용이없는 인라인 어셈블리 코드는 GCC에 의해 삭제 될 위험이 있습니다. volatile 키워드를 asm 문에 추가하면 이러한 제거가 방지됩니다.
jiffies 변수는 참조 될 때마다 다른 값을 가질 수 있다는 점에서 특별하지만 특별한 잠금없이 읽을 수 있습니다. 따라서 지프는 휘발성이 될 수 있지만이 유형의 다른 변수를 추가하는 것은 매우 어려워집니다. Jiffies는 이와 관련하여 "멍청한 유산"문제 (Linus의 말)로 간주됩니다. 그것을 고치는 것은 가치보다 더 문제가 될 것입니다.
I / O 장치에 의해 수정 될 수있는 코 히어 런트 메모리의 데이터 구조에 대한 포인터는 때때로 합법적으로 휘발성 일 수 있습니다. 네트워크 어댑터가 사용하는 링 버퍼 (어댑터가 포인터를 변경하여 처리 된 디스크립터를 표시 함)는 이러한 유형의 상황의 예입니다.
대부분의 코드에서 휘발성에 대한 위의 근거 중 어느 것도 적용되지 않습니다. 결과적으로 휘발성의 사용은 버그로 보일 수 있으며 코드를 추가로 조사합니다. 휘발성을 사용하려는 개발자는 한 발짝 물러서서 진정으로 달성하려는 것에 대해 생각해야합니다.