'KeAcquireInStackQueuedSpinLock'에 해당되는 글 1건

  1. 2012.02.01 [윈도우 NT] KeAcquireInStackQueuedSpinLock 2
Windows OS2012. 2. 1. 00:15
반응형
앞에서 KeAcquireQueuedSpinLock() 함수에 대해 알아 봤다.

http://greemate.tistory.com/entry/KeAcquireQueuedSpinLock

이 좋은 것을 왜 서드파티 개발자들은 사용할 수 없을까?
그래서 마련된 것이 KeAcquireInStackQueuedSpinLock()이다.

KeAcquireQueuedSpinLock()은 PCR(Processor Control Region)에 락에 대한 변수를 선언해 놨기 때문에 서드 파티 개발자들이 사용할 수 없다는 것은 어찌보면 당연한 말이다.

그렇다면 KeAcquireInStackQueuedSpinLock()은 이 문제를 어떻게 해결한 것일까?
먼저 함수 프로토타입을 보자.

VOID 
KeAcquireInStackQueuedSpinLock(

  __inout  PKSPIN_LOCK SpinLock,

  __out    PKLOCK_QUEUE_HANDLE LockHandle

);

VOID 
KeReleaseInStackQueuedSpinLock(

  __in  PKLOCK_QUEUE_HANDLE LockHandle

); 


핵심은 KLOCK_QUEUE_HANDLE에 있다.
KLOCK_QUEUE_HANDLE이 PCR에 정의된 QueuedSpinLock 역할을 대신해 주면서 동일한 방식으로 동작한다.

KLOCK_QUEUE_HANDLE 구조는 공개되지 않았지만 분석해 보면 아래와 같은 필드를 가진다. (첨부파일 참조)

typedef struct _KLOCK_QUEUE_HANDLE  
{
    struct _KLOCK_QUEUE_HANDLE *pNext;
    PKSPIN_LOCK pLock;
    KIRQL OldIrql;
} KLOCK_QUEUE_HANDLE, *PKLOCK_QUEUE_HANDLE; 


QueuedSpinLock이 가지고 있던 pLock, pNext를 그대로 가지고 있다.
추가로 OldIrql 필드도 있다.

함수 프로토타입을 보면 KeAcquireInStackQueuedSpinLock() 함수는 IRQL을 리턴하는 부분이 없는데 Acquire하면서 OldIrql 필드에 직접 저장해 주기 때문에 굳이 함수의 리턴값일 필요가 없다. 
KeReleaseInStackQueuedSpinLock() 함수도 LockHandle만 넘겨주면 저장된 OldIrql을 사용하기 때문에 굳이 IRQL을 파라미터로 받지 않아도 된다.

여기서 주의해야 할 사항은 함수이름이 InStack인 이유가 있다는 것이다.
첫번째 파라미터인 SpinLock은 전역변수거나 지역변수거나 상관없지만 두번째 파라미터인 LockHandle은 반드시 지역변수로 선언해서 스택에 존재하게 해야 한다.

황당하게도 이 중요한 사실이 MSDN에는 나와있지 않다.
다행히도 Windows Internals에서는 잘 설명해 주고 있다.

KeAcquireQueuedSpinLock() 함수는 CPU마다의 PCR을 사용했기 때문에 CPU1의 PCR과 CPU2의 PCR 주소가 다르고, 서로 다른 메모리 영역이라서 pLock도 각각 가지고 있고, pNext에 주소를 기록해서 링크로 연결할 수 있었다.

KeAcquireInStackQueuedSpinLock() 함수에서는 LockHandle이 PCR 영역의 역할을 하는 것인데 만약 이것이 전역변수라면 CPU1과 CPU2가 사용하는 메모리가 같아진다는 뜻이다. 
CPU1과 CPU2가 pLock 변수를 같은 것을 쓰게 되어 각자 특정 비트를 셋팅할 수도 없고 pNext 링크도 자기 자신을 연결해 버리는 셈이 되니 엉망이 되고 말 것이다.

따라서 KeAcquireInStackQueuedSpinLock()를 호출하는 곳에서는 LockHandle을 지역변수로 선언해 현재 스레드 스택의 메모리가 사용되도록 하면 되는 것이다. (모든 스레드는 각자 고유의 스택영역을 가지고 있으니 말이다.)
설명하면서 생각해 보니 호출 직전에 할당한 메모리를 사용해도 문제가 없을 것 같다.
전역변수만 아니면 되겠다.

이제 개발자들도 QueuedSpinLock을 사용할 수 있다. ^^
아쉽게도 이 함수는 XP이상에서만 지원한다.

  

반응형
Posted by GreeMate