스핀락의 구현
스핀락에 대해 어렵게 생각하시는 분들이 많으시더군요. 실제 구현은 간단합니다.
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일에 작성된 글을 옮겨온 것입니다.