새 드라이버는 이 섹션에 설명된 메서드보다 취소로부터 안전한 IRP 큐 프레임워크를 사용하는 것이 좋습니다.
시스템 플로피 컨트롤러 드라이버와 마찬가지로 StartIo 루틴이 아닌 디바이스 전용 스레드를 사용하는 드라이버는 일반적으로 이중으로 연결된 연동 큐에서 자체 IRP 큐를 관리합니다. 드라이버의 스레드는 디바이스에서 수행해야 할 작업이 있을 때 연동된 큐에서 IRP를 끌어온다.
일반적으로 드라이버는 스레드와 다른 드라이버 루틴 간에 공유되는 모든 리소스에 대한 스레드와의 동기화를 관리해야 합니다. 또한 드라이버가 드라이버 생성 스레드에 IRP가 큐에 들어가 있음을 알리는 방법도 있어야 합니다. 일반적으로 스레드는 IRP를 연동된 큐에 삽입한 후 드라이버의 디스패치 루틴이 디스패처 개체를 Signaled 상태로 설정할 때까지 디바이스 확장에 저장된 디스패처 개체에서 대기합니다.
드라이버의 디스패치 루틴이 호출되면 각각 입력 IRP의 I/O 스택 위치에서 매개 변수를 확인하고 유효한 경우 추가 처리를 위해 요청을 큐에 대기합니다. 드라이버 전용 스레드에 대기 중인 각 IRP에 대해 디스패치 루틴은 ExInterlockedInsertXxx목록을 호출하기 전에 해당 스레드가 해당 IRP를 처리하는 데 필요한 컨텍스트를 설정해야 합니다. 각 IRP에서 드라이버의 I/O 스택 위치는 드라이버의 스레드가 대상 장치 객체의 장치 확장에 접근할 수 있도록 하며, 이는 스레드가 큐에서 각 IRP를 제거할 때 드라이버가 스레드와 컨텍스트 정보를 공유할 수 있게 해줍니다.
취소 가능한 IRP를 큐에 대기하는 드라이버는 취소 루틴을 구현해야 합니다. IRP는 비동기적으로 취소되므로 드라이버가 발생할 수 있는 레이스 컨디션(경합 조건)을 방지해야 합니다. IRP 취소 동기화 참고하여 IRP 취소와 관련된 경합 조건 및 이를 방지하는 기술에 대해 더 알아보세요.
드라이버가 만든 스레드는 IRQL = PASSIVE_LEVEL 및 드라이버가 PsCreateSystemThread를 호출할 때 이전에 설정한 기본 런타임 우선 순위에서 실행됩니다. ExInterlockedRemoveHeadList에 대한 스레드의 호출은 IRP가 드라이버의 내부 큐에서 제거되는 동안 현재 프로세서에서 IRQL을 DISPATCH_LEVEL로 일시적으로 상승시킵니다. 이 호출에서 반환될 때 원래 IRQL이 PASSIVE_LEVEL로 복원됩니다.
드라이버 스레드(또는 드라이버가 제공한 워커 스레드 콜백)는 실행되는 IRQL을 신중하게 관리해야 합니다. 예를 들어 다음을 고려합니다.
시스템 스레드는 일반적으로 IRQL = PASSIVE_LEVEL 실행되므로 드라이버 스레드가 커널 정의 디스패처 개체가 신호 상태로 설정될 때까지 대기할 수 있습니다.
예를 들어 디바이스 전용 스레드는 다른 드라이버가 이벤트를 충족하고 스레드가 IoBuildSynchronousFsdRequest로 설정한 일부 부분 전송 IRP를 완료할 때까지 기다릴 수 있습니다.
그러나 이러한 디바이스 전용 스레드는 특정 지원 루틴을 호출하기 전에 현재 프로세서에서 IRQL을 발생시켜야 합니다.
예를 들어 드라이버가 DMA를 사용하는 경우 디바이스 전용 스레드는 이러한 루틴과 DMA 작업에 대한 특정 다른 지원 루틴을 IRQL = DISPATCH_LEVEL 호출해야 하기 때문에 KeRaiseIrql 및 KeLowerIrql 호출 사이에 AllocateAdapterChannel 및 FreeAdapterChannel에 대한 호출을 중첩해야 합니다.
StartIo 루틴은 DISPATCH_LEVEL 실행되므로 DMA를 사용하는 드라이버는 StartIo 루틴에서 KeXxxIrql 루틴을 호출할 필요가 없습니다.
드라이버에서 생성한 스레드는 IRQL = PASSIVE_LEVEL의 임의적이지 않은 스레드 컨텍스트(자체)에서 실행되기 때문에 페이저블 메모리에 접근할 수 있으나, 많은 다른 표준 드라이버 루틴은 IRQL >= DISPATCH_LEVEL에서 실행됩니다. 드라이버에서 만든 스레드가 이러한 루틴에서 액세스할 수 있는 메모리를 할당하는 경우 페이지가 없는 풀에서 메모리를 할당해야 합니다. 예를 들어, 디바이스 전용 스레드가 드라이버의 ISR 또는 SynchCritSection, AdapterControl, AdapterListControl, ControllerControl, DpcForIsr, CustomDpc, IoTimer, CustomTimerDpc 또는 상위 수준 드라이버의 IoCompletion 루틴에 의해 나중에 액세스될 버퍼를 할당하는 경우, 스레드가 할당한 메모리는 페이지 가능하지 않아야 합니다.
드라이버가 디바이스 확장에서 공유 상태 정보 또는 리소스를 유지 관리하는 경우 드라이버 스레드(예: StartIo 루틴)는 물리적 디바이스 및 공유 데이터에 대한 액세스를 동일한 디바이스, 메모리 위치 또는 리소스에 액세스하는 드라이버의 다른 루틴과 동기화해야 합니다.
스레드가 ISR과 디바이스 또는 상태를 공유하는 경우 KeSynchronizeExecution 을 사용하여 드라이버 제공 SynchCritSection 루틴을 호출하여 디바이스를 프로그래밍하거나 공유 상태에 액세스해야 합니다. 중요 섹션 사용을 참조하세요.
스레드가 ISR 이외의 루틴과 상태 또는 리소스를 공유하는 경우 드라이버는 드라이버가 스토리지를 제공하는 드라이버 초기화된 임원 스핀 잠금으로 공유 상태 또는 리소스를 보호해야 합니다. 자세한 내용은 스핀 잠금을 참조하세요.
느린 디바이스에 대한 드라이버 스레드 사용의 디자인 장단분에 대한 자세한 내용은 디바이스 폴링을 참조하세요. 하드웨어 우선 순위 관리도 참조하세요. 특정 지원 루틴에 대한 IRQL에 대한 자세한 내용은 루틴의 참조 페이지를 참조하세요.