Linux Kernel 의 Memory barrier 구현

Linux Kernel의 프로세스 상태 변경 매크로(set_task_state, set_current_state)를 살펴보다가 ARM 아키텍처에서 다음과 같이 구현된 것을 보았다.

include/linux/sched.h

#define set_task_state(tsk, state_value)        \
    set_mb((tsk)->state, (state_value))
#define set_current_state(state_value)        \
    set_mb(current->state, (state_value))

set_mb 매크로는 시스템마다 다르게 구현되어 있는데 ARM 쪽을 따라가보면 다음과 같이 쓰여져 있다.

arch/arm/include/asm/system.h

#define dmb() __asm__ __volatile__ (“” : : : “memory”)

#define smp_mb()    dmb()

#define set_mb(var, value)    do { var = value; smp_mb(); } while (0)

do-while-0 구문에 대해서는 이 글을 참고하도록 하고, memory barrier에 대해서는 이 글을 참고하라. dmb() 의 inline assembly의 구조와 설명은 이 글을 참고하자.

참고된 글을 정리하자면, 명령이 R, W, R, W, R, W 순으로 사용된다면, 이를 하드웨어 혹은 소프트웨어 적으로 R, R, R, W, W, W 순으로 배열하는 등의 최적화를 할 수 있는데, 이 때 명령의 순서를 보장해 주는 역할로써 Memory barrier 라는 것을 구현해서 사용한다. 이는 하드웨어적으로 혹은 소프트웨어적으로 구현되는데 하드웨어적인 방법은 CPU 자체의 명령으로 구현되는 등의 방법이 사용될 수 있고, 소프트웨어적으로 구현될 때 위와 같이 구현될 수 있다.
위 구문은 gcc inline assembly의 확장으로 clobber list에 “memory”를 적어넣어 해당 명령(“” – 아무 명령도 수행하지 않음)을 수행한 후에 변경되는 것이 메모리 타입 저장장치(모든 레지스터, 모든 플래그, 모든 메모리)임을 나타낸다. gcc는 이럴경우 __asm__ __volatile__(“”: : :”memory”) 경계를 넘어가는 최적화 또는 instruction scheduling을 수행하지 않기 때문에 __asm__ __volatile__(“”: : :”memory”)를 사용하면 이전 코드의 수행 완료를 보장할 수 있고 이후 코드가 __asm__ __volatile__(“”: : :”memory”) 이전에 수행되는것을 방지 할수 있다. 별개로 volatile의 경우 읽기 연산에서 메모리에서 한번 읽어온 데이터를 레지스터에 저장해서 사용하는 것이 아닌 사용할 때마다 메모리 참조를 통해 가져오도록 한다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다