스핀락에 대해 어렵게 생각하시는 분들이 많으시더군요. 실제 구현은 간단합니다.

static inline void arch_spin_lock(arch_spinlock_t *lock)
{
    unsigned long tmp;
    /*
     * 스핀락의 ARM 아키텍쳐 구현입니다.
     * 1. lock->lock의 값을 가져와서 tmp에 저장합니다. 
     *    배타적 로드(ldrex)를 썼기 때문에 이후에 오는 배타적
     *    스토어(strex)가 오기 까지 변경이 되었는지 
     *    하드웨어가 검증합니다.
     * 2. 값이 0인지 확인하여, 0인 경우에만 lock->lock에 1을
     *    저장합니다.
     * 3. 배타적 로드와 스토어 사이에 lock->lock의 값의 변경이
     *    있었다면 1로 돌아가서 반복합니다.
     * 4. 완료가 되었다면 smp_mb를 호출하여 메모리 베리어를
     *    사용합니다. 메모리 베리어에 의해 lock->lock의
     *    (SMP에서도) 변경 된 값이 이용되는게 보장됩니다.
     */
    __asm__ __volatile__(
"1: ldrex   %0, [%1]\n"
"   teq %0, #0\n"
    WFE("ne")
"   strexeq %0, %2, [%1]\n"
"   teqeq   %0, #0\n"
"   bne 1b"
    : "=&r" (tmp)
    : "r" (&lock->lock), "r" (1)
    : "cc");

    smp_mb();
}

위의 코드는 리눅스 커널에 ARM용으로 스핀락을 구현된 곳입니다. 주석은 제가 달았습니다. 간단하게 루프를 돌면서 기다리는 것을 볼 수 있습니다.

퀴즈: 인텔에는 배타적 로드/스토어(ldrex, strex)가 없는데 구현을 어떻게 했을까요?

PS: 이 글은 2015년 7월 10일에 작성된 글을 옮겨온 것입니다.