Поделиться через


Использование __sdv_save_request и __sdv_retrieve_request для вызовов отложенных процедур

Вызовы отложенных процедур (DPCs) создают трудности для средства проверки статических драйверов (SDV), так как трудно отслеживать объект запроса фреймворка. Одна из трудностей заключается в том, что запрос должен быть получен из глобального указателя, как правило, из контекста очереди или из рабочего элемента. Чтобы преодолеть эту трудность, средство проверки статических драйверов предоставляет две функции: __sdv_save_request и __sdv_retrieve_request. Эти функции сопоставляют отложенный запрос с запросом, который SDV может отслеживать.

Функции __sdv_save_request и __sdv_retrieve_request имеют следующий синтаксис:

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

Где запрос может быть дескриптором для любого объекта запроса платформы.

Эти функции используются только средствами статического анализа. Функции игнорируются компилятором.

В следующем примере кода показано, как функции __sdv_save_request и __sdv_retrieve_request используются для управления SDV, чтобы SDV могли сопоставить отложенный запрос. SDV может использовать это сопоставление для проверки правила DeferredRequestCompleted . Для правила DeferredRequestCompleted требуется, чтобы в коде отображались __sdv_save_request и __sdv_retrieve_request . Существует два правила свойств драйвера (AliasWithinDispatch, AliasWithinTimerDpc), которые ищут существование функций __sdv_save_request и __sdv_retrieve_request .

В следующем примере кода функция EchoEvtIoRead — это функция обратного вызова события EvtIoRead, которая сохраняет дескриптор объекта запроса фреймворка в контекстной области очереди. Функция EchoEvtTimerFunc — это функция обратного вызова события EvtTimerFunc , извлекающая ее.

VOID
EchoEvtIoRead(
 )in WDFQUEUE   Queue,
 __in WDFREQUEST Request,
 __in size_t      Length
    )
{
/* ..................... */
    // Mark the request as cancelable
    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);
 
 
    // Defer the completion to another thread from the timer DPC and save the handle to the framework request object by using the __sdv_save_request function. 
    queueContext->CurrentRequest = Request;    
 __sdv_save_request(Request);

    queueContext->CurrentStatus  = Status;

    return;
}

В следующем примере кода показано, как функция __sdv_retrieve_request сопоставляет существующий запрос, чтобы SDV могли отслеживать его для завершения.

VOID
EchoEvtTimerFunc(
    IN WDFTIMER     Timer
    )
{...................................................
    queue = WdfTimerGetParentObject(Timer);
    queueContext = QueueGetContext(queue);

    //
    // The DPC is automatically synchronized to the queue lock,
    // so this prevents race conditions from occurring without explicit driver-managed locking. The __sdv_retrieve_request function is used so that SDV can restore the deferred request in the timer DPC. Because we know that this deferred request is valid (because it has been previously saved), the __analysis_assume function is used to suppress false defects that might otherwise result in this code path.

    //
 __sdv_retrieve_request(queueContext->CurrentRequest);
    Request = queueContext->CurrentRequest;
 __analysis_assume(Request != NULL);
    if( Request != NULL ) {

        //
        // Try to remove cancel status from the request.
        //
        // The request is not completed if it is already canceled
        // because the EchoEvtIoCancel function has run, or is about to run,
        // and we are racing with it. 

        Status = WdfRequestUnmarkCancelable(Request);
// Because we know that the request is not NULL in this code path and that the request is no longer marked cancelable, we can use the __analysis_assume function to suppress the reporting of a false defect. 

 __analysis_assume(Status != STATUS_CANCELLED);
        if( Status != STATUS_CANCELLED ) {

            queueContext->CurrentRequest = NULL;
            Status = queueContext->CurrentStatus;

            KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status));

            WdfRequestComplete(Request, Status);
        }
        else {
            KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n",
                                Request));
        }
    }

    return;
}