다음을 통해 공유


인터럽트 코드 동기화

다음 요인은 다중 프로세서 시스템의 하드웨어 인터럽트를 처리하는 드라이버 코드를 복잡하게 만듭니다.

  • 디바이스가 중단될 때마다 다음에 디바이스가 중단될 때 덮어쓸 수 있으므로 일시적 인터럽트 관련 정보를 제공합니다.

  • 디바이스는 비교적 높은 IRQL에서 중단되며 ISR(인터럽트 서비스 루틴)은 다른 드라이버 코드의 실행을 방해할 수 있습니다.

  • DIRQL 인터럽트인 경우 ISR은 드라이버 제공 스핀 잠금을 유지하면서 DIRQL에서 실행되어야 하므로 ISR은 휘발성 정보를 저장하는 동안 추가 인터럽트 방지를 수행할 수 있습니다. DIRQL은 현재 프로세서의 중단을 방지하고 스핀 잠금은 다른 프로세서의 중단을 방지합니다.

  • ISR이 실행되는 동안 디바이스가 중단될 수 없으므로 ISR이 신속하게 실행되어야 합니다. ISR 실행 시간이 길면 시스템이 느려지거나 데이터 손실이 발생할 수 있습니다.

  • ISR 및 DPC(지연 프로시저 호출) 루틴은 일반적으로 ISR이 디바이스의 휘발성 데이터를 저장하는 스토리지 영역에 액세스해야 합니다. 이러한 루틴은 스토리지 영역에 동시에 액세스하지 않도록 서로 동기화해야 합니다.

이러한 모든 요소 때문에 인터럽트 처리 드라이버 코드를 작성할 때 다음 규칙을 사용해야 합니다.

  • EvtInterruptIsr 콜백 함수만 인터럽트 정보를 포함하는 디바이스 레지스터와 같은 휘발성 인터럽트 데이터에 액세스합니다.

    EvtInterruptIsr 콜백 함수는 드라이버의 EvtInterruptDpc 콜백 함수, EvtInterruptWorkItem 콜백 함수 또는 여러 EvtDpcFunc 콜백 함수가 액세스할 수 있는 드라이버 정의 인터럽트 데이터 버퍼로 휘발성 데이터를 이동해야 합니다.

    드라이버가 인터럽 트 개체에 대해 EvtInterruptDpc 또는 EvtInterruptWorkItem 콜백 함수를 제공하는 경우 인터럽트 데이터를 저장하는 가장 좋은 위치는 인터럽트 개체의 컨텍스트 공간입니다. 인터럽트 개체의 콜백 함수는 수신하는 개체 핸들을 사용하여 개체의 컨텍스트 공간에 액세스할 수 있습니다.

    드라이버가 각 EvtInterruptIsr 콜백 함수에 대해 여러 EvtDpcFunc 콜백 함수를 제공하는 경우 각 DPC 개체의 컨텍스트 공간에 인터럽트 데이터를 저장할 수 있습니다.

  • 인터럽트 데이터 버퍼에 액세스하는 모든 드라이버 코드는 한 번에 하나의 루틴만 데이터에 액세스할 수 있도록 동기화되어야 합니다.

    DIRQL 인터럽트 개체의 경우 EvtInterruptIsr 콜백 함수는 인터럽트 개체의 드라이버 제공 스핀 잠금을 유지하면서 IRQL = DIRQL에서 이 데이터 버퍼에 액세스합니다. 따라서 버퍼에 액세스하는 모든 루틴은 스핀 잠금을 유지하는 동안 DIRQL에서도 실행되어야 합니다. (일반적으로 인터럽트의 EvtInterruptDpc 또는 EvtDpcFunc 콜백 함수는 버퍼에 액세스해야 하는 유일한 다른 루틴입니다.)

    EvtInterruptIsr 콜백 함수를 제외하고 인터럽트 데이터 버퍼에 액세스하는 모든 루틴은 다음 중 하나를 수행해야 합니다.

    이러한 두 기술을 모두 사용하면 EvtInterruptDpc 또는 EvtDpcFunc 함수가 인터럽트의 스핀 잠금을 유지하면서 DIRQL의 인터럽트 데이터에 액세스할 수 있습니다. DIRQL은 현재 프로세서의 중단을 방지하고 스핀 잠금은 다른 프로세서의 중단을 방지합니다.

    디바이스가 여러 인터럽트 벡터 또는 메시지를 지원하고 이러한 인터럽트의 드라이버 처리를 동기화하려는 경우 여러 DIRQL 인터럽트 개체에 단일 스핀 잠금을 할당할 수 있습니다. 프레임워크는 인터럽트 집합 중 가장 높은 DIRQL을 결정하고 항상 해당 DIRQL에서 스핀 잠금을 획득하므로 동기화된 코드가 집합의 인터럽트 벡터 또는 메시지에 의해 중단될 수 없습니다.

    수동 수준 인터럽트 개체의 경우 프레임워크는 IRQL = PASSIVE_LEVEL 드라이버의 EvtInterruptIsr 콜백 함수를 호출하기 전에 수동 수준 인터럽트 잠금을 획득합니다. 따라서 버퍼에 액세스하는 모든 루틴은 인터럽트 잠금을 획득하거나 내부적으로 버퍼 액세스를 동기화해야 합니다. 일반적으로 인터럽트의 EvtInterruptWorkItem 콜백 함수는 버퍼에 액세스하는 유일한 다른 루틴입니다. EvtInterruptWorkItem 콜백 함수에서 인터럽트 잠금을 획득하는 방법에 대한 자세한 내용은 해당 페이지의 설명 섹션을 참조하세요.

    단일 대기 잠금을 여러 수동 수준 인터럽트 개체에 할당하여 드라이버의 여러 인터럽트 벡터 처리를 동기화할 수도 있습니다.

  • DIRQL 인터럽트를 처리하는 일부 코드가 IRQL = PASSIVE_LEVEL 실행되어야 하는 경우 EvtInterruptDpc 또는 EvtDpcFunc 콜백 함수는 코드가 EvtWorkItem 콜백 함수로 실행되도록 하나 이상의 작업 항목을 만들 수 있습니다.

    또는 KMDF 버전 1.11 이상에서 드라이버는 WdfInterruptQueueWorkItemForIsr를 호출하여 인터럽트 작업 항목을 요청할 수 있습니다. (드라이버의 EvtInterruptIsr 콜백 함수는 WdfInterruptQueueWorkItemForIsr 또는 WdfInterruptQueueDpcForIsr를 호출할 수 있지만 둘 다 호출할 수는 없습니다.)

  • 드라이버의 EvtInterruptDpcEvtDpcFunc 콜백 함수를 서로 동기화하고 디바이스와 연결된 다른 콜백 함수와 동기화하는 것이 중요한 경우 드라이버는 인터럽트의 WDF_INTERRUPT_CONFIG 구조와 DPC 개체의 WDF_DPC_CONFIG 구조에서 AutomaticSerialization 멤버를 TRUE로 설정할 수 있습니다. 또는 드라이버가 프레임워크 스핀 잠금을 사용할 수 있습니다. AutomaticSerialization 멤버를 TRUE로 설정해도 EvtInterruptIsr 콜백 함수는 다른 콜백 함수와 동기화되지 않습니다. 이 항목의 앞부분에서 설명한 대로 WdfInterruptSynchronize 또는 WdfInterruptAcquireLock을 사용하여 EvtInterruptIsr 콜백 함수를 동기화합니다.)

드라이버 루틴 동기화에 대한 자세한 내용은 Framework-Based 드라이버용 동기화 기술을 참조하세요.