세마포 개체

모든 드라이버는 세마포 개체를 사용하여 드라이버에서 만든 스레드와 다른 드라이버 루틴 간에 작업을 동기화할 수 있습니다. 예를 들어 드라이버 전용 스레드는 드라이버에 대한 미해결 I/O 요청이 없는 경우 대기 상태로 전환될 수 있으며, 드라이버의 디스패치 루틴은 IRP를 큐에 대기한 직후에 세마포를 Signaled 상태로 설정할 수 있습니다.

I/O 작업을 요청하는 스레드의 컨텍스트에서 실행되는 최상위 드라이버의 디스패치 루틴은 세마포를 사용하여 디스패치 루틴 간에 공유되는 리소스를 보호할 수 있습니다. 동기 I/O 작업에 대한 하위 수준 드라이버 디스패치 루틴은 세마포를 사용하여 해당 디스패치 루틴의 하위 집합 또는 드라이버에서 만든 스레드와 공유되는 리소스를 보호할 수도 있습니다.

세마포 개체를 사용하는 모든 드라이버는 세마포를 기다리거나 해제하기 전에 KeInitializeSemaphore 를 호출해야 합니다. 다음 그림에서는 스레드가 있는 드라이버가 세마포 개체를 사용하는 방법을 보여 줍니다.

세마포 개체를 기다리는 모습을 보여 주는 다이어그램

이전 그림과 같이 이러한 드라이버는 상주해야 하는 세마포 개체에 대한 스토리지를 제공해야 합니다. 드라이버는 드라이버에서 만든 디바이스 개체의 디바이스 확장 , 컨트롤러 개체를 사용하는 경우 컨트롤러 확장 또는 드라이버가 할당한 비페이지 풀을 사용할 수 있습니다.

드라이버의 AddDevice 루틴이 KeInitializeSemaphore를 호출하는 경우 세마포 개체에 대한 드라이버의 상주 스토리지에 대한 포인터를 전달해야 합니다. 또한 호출자는 이전 그림과 같이 초기 상태(Signaled의 경우 0이 아닌 경우)를 결정하는 세마포 개체에 대한 Count 를 지정해야 합니다.

호출자는 다음 중 하나일 수 있는 세마포에 대한 제한을 지정해야 합니다.

  • 제한 = 1

    이 세마포가 Signaled 상태로 설정되면 세마포가 Signaled 상태로 설정되기를 기다리는 단일 스레드가 실행에 적합해지고 세마포로 보호되는 모든 리소스에 액세스할 수 있습니다.

    스레드에 세마포로 보호된 리소스에 대한 단독 액세스 권한이 있거나 없는 스레드이기 때문에 이 유형의 세마포를 이 진 세마 포라고도 합니다.

  • 제한 > 1

    이 세마포가 Signaled 상태로 설정되면 세마포 개체가 Signaled 상태로 설정되기를 기다리는 일부 스레드가 실행될 수 있으며 세마포로 보호되는 리소스에 액세스할 수 있습니다.

    세마포를 Signaled 상태로 설정하는 루틴은 대기 상태에서 준비 상태로 상태를 변경할 수 있는 대기 스레드 수를 지정하기 때문에 이러한 유형의 세 마포를 카운팅 세마포 라고 합니다. 이러한 대기 스레드의 수는 세마포가 초기화되었을 때 설정된 제한 또는 이 미리 설정된 제한보다 적은 수일 수 있습니다.

드라이버에서 만든 단일 스레드가 있는 디바이스 또는 중간 드라이버는 거의 없습니다. 세마포를 획득하거나 해제할 때까지 기다릴 수 있는 스레드 집합이 더 적습니다. 시스템 제공 드라이버가 세마포 개체를 사용하는 경우는 거의 없으며, 그 중에서도 이진 세마포를 사용하는 드라이버가 적습니다. 이진 세마포는 뮤텍스 개체와 기능면에서 유사한 것처럼 보일 수 있지만, 이진 세마포는 SMP 머신에서 실행되는 시스템 스레드에 대해 뮤텍스 개체가 갖는 교착 상태에 대한 기본 제공 보호를 제공하지 않습니다.

초기화된 세마포가 있는 드라이버가 로드되면 공유 리소스를 보호하는 세마포에 대한 작업을 동기화할 수 있습니다. 예를 들어 시스템 플로피 컨트롤러 드라이버와 같은 IRP의 큐를 관리하는 디바이스 전용 스레드가 있는 드라이버는 이전 그림과 같이 세마포에서 IRP 큐를 동기화할 수 있습니다.

  1. 스레드는 초기화된 세마포 개체에 대해 드라이버 제공 스토리지에 대한 포인터를 사용하여 KeWaitForSingleObject 를 호출하여 대기 상태로 전환합니다.

  2. 디바이스 I/O 작업이 필요한 IRP가 들어오기 시작합니다. 드라이버의 디스패치 루틴은 이러한 각 IRP를 스핀 잠금 제어 아래의 인터락된 큐에 삽입하고 세마포 개체에 대한 포인터, 스레드에 대한 드라이버 결정 우선 순위 상승(이전 그림과 같이 증가), 각 IRP가 큐에 대기할 때 세마포의 개수에 추가된 1의 조정 및 부울 대기 집합을 FALSE로 설정하여 KeReleaseSemaphore를 호출합니다. 0이 아닌 세마포 개수는 세마포 개체를 Signaled 상태로 설정하여 대기 스레드의 상태를 준비 상태로 변경합니다.

  3. 커널은 프로세서를 사용할 수 있는 즉시 실행을 위해 스레드를 디스패치합니다. 즉, 우선 순위가 높은 다른 스레드가 현재 준비 상태에 있지 않으며 더 높은 IRQL에서 실행할 커널 모드 루틴이 없습니다.

    스레드는 스핀 잠금 제어 아래의 연동된 큐에서 IRP를 제거하고, 추가 처리를 위해 다른 드라이버 루틴에 전달하고, KeWaitForSingleObject를 다시 호출합니다. 세마포가 여전히 신호됨 상태로 설정된 경우(즉, 해당 개수가 0이 아닌 상태로 유지되어 더 많은 IRP가 드라이버의 연동 큐에 있음을 나타남) 커널은 스레드 상태를 대기 중에서 준비 상태로 다시 변경합니다.

    이러한 방식으로 카운팅 세마포를 사용하면 이러한 드라이버 스레드는 해당 스레드가 실행될 때마다 인터링된 큐에서 제거할 IRP가 "알고 있다"고 합니다.

KeReleaseSemaphore를 호출할 때 IRQL을 관리하는 방법에 대한 자세한 내용은 KeReleaseSemaphore의 설명 섹션을 참조하세요.

PASSIVE_LEVEL보다 큰 IRQL에서 실행되는 표준 드라이버 루틴은 시스템을 중단하지 않고 디스패처 개체에서 0이 아닌 간격을 기다릴 수 없습니다. 자세한 내용은 커널 디스패처 개체 를 참조하세요. 그러나 이러한 루틴은 DISPATCH_LEVEL 이하의 IRQL에서 실행되는 동안 KeReleaseSemaphore 를 호출할 수 있습니다.

표준 드라이버 루틴이 실행되는 IRQL에 대한 요약은 하드웨어 우선 순위 관리를 참조하세요. 특정 지원 루틴의 IRQL 요구 사항은 루틴의 참조 페이지를 참조하세요.