atomic_set 연산에 대하여

start_kernel() -> cgroup_init_early 함수를 보면 아래와 같은 코드가 있습니다.

atomic_set(&init_css_set.refcount, 1);

그런데, atomic_set 매크로는 아래와 같이 되어있군요.

#define atomic_set(v,i) (((v)->counter) = (i))

왜 그냥 init_css_set.refcount = 1 과 같이 하면 될 것을 굳이 이렇게 한꺼풀을 씌워서 어려워보이게 해두었을까요?
Patch History 를 보니 원래 atomic_set 은 아래와 같이 구현되어 있었네요.
http://lists.infradead.org

static inline void atomic_set(atomic_t *v, int i)
{
unsigned long tmp;
__asm__ __volatile__("@ atomic_set\n"
    "1: ldrex %0, [%1]\n"
    " strex %0, %2, [%1]\n"
    " teq %0, #0\n"
    " bne 1b"
    : "=&r" (tmp)
    : "r" (&v->counter), "r" (i)
    : "cc");
}

즉, 다른 atomic_add 나 atomic_sub 처럼 ldrex 와 strex 를 함께 사용하는 방식으로 구현되어 있었습니다.
이를 str 연산 하나로 대체해버린 주요한 원인은 아래의 문구에서 보듯이 store 연산도 Global exclusive monitor 를 clear 해줄 수 있게 되었기 때문인 것 같습니다.

With this patch, the atomic_set() operation can be a simple STR instruction (on SMP systems, the global exclusive monitor is cleared by STR anyway). Clearing the exclusive monitor during context switch is no longer needed as this is handled by the exception return path anyway.

즉, atomic_set 연산을 제대로 atomic 하게 구현하려면, store 하는 자신의 연산 뿐 아니라 자신의 연산을 다른 atomic 연산이 알아챌 수 있어야 합니다. 그런데, 만약 store 연산이 exclusive monitor 를 clear 하지 않는다면 이를 다른 연산이 알아챌 수 없을겁니다.
예를 들어, 아래 상황에서 store 연산이 exclusive monitor 를 clear 하지 않으면 ?.

  • 1 번 코어의 프로그램이 ldrex 를 수행한다. (local, global monitor 설정 – tag memory, exclusive 상태)
  • 2 번 코어의 프로그램이 str 연산 수행 (global monitor clear X)
  • 1 번 코어의 프로그램이 정상적으로 strex 수행

아마도 위와 같이 1 번 코어에서 수행되는 프로그램은 중간에 변경된 것을 눈치채지 못하고 이전에 로드한 값을 변경한 결과를 저장해 버릴 것입니다.
이는 store 연산이 다른 atomic 연산을 비정상적으로 만드는 상황이 됩니다. 이 때문에 이전에는 atomic_set 도 ldrex 와 strex 연산을 이용했었던 것 같습니다. (exclusive monitor 를 변경할 수 있는 명령)
그러다가,store 연산도 global exclusive monitor 를 clear 하도록 변경이 되었고, 이렇게 되면 다른 atomic 연산들은 monitor 가 변경되었을 때 status 값을 검사하여 변경 여부를 감지할 수 있습니다.
결국, atomic_set 연산 자체는 store 연산 하나만으로도 충분하게 된 것이므로, 성능 안좋게 굳이 ldrex 와 strex 를 함께 사용할 필요가 없게 된 것입니다. 이러한 atomic_set 에 대한 inline assembly 코드는 없어지고 결국 = (store) 만 남게 된 것입니다.


References:
1. http://www.iamroot.org/xe/Kernel_8_ARM/66152
2. linux-3.12.20/arch/arm/include/asm/atomic.h
3. linux-3.12.20/Document/atomic_ops.txt
4. http://lists.infradead.org

You may also like...