roger_chen35
驱动牛犊
驱动牛犊
  • 注册日期2002-11-19
  • 最后登录2004-04-29
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1436回复:0

关于KeEnterCriticalRegion and APC

楼主#
更多 发布于:2004-04-02 08:27
请教各位大侠两个问题

1.什么是 general kernel mode apc and
  special kernel mode apc ?

2.DDK说 KeEnterCriticalRegion and KeLeaveCriticalRegion
  是用来 disable user mode apc and general kernel mode apc
  防止 current thread 被 apc suspend , 可是我一直不懂
  currend thread 如何被 apc suspend ?

以下是小弟参考 DDK sample code 的 toaster 看到的 sample 就是不了解 KeEnterCriticalRegion and KeLeaveCriticalRegion 中间的机制是什么


BOOLEAN
ToasterArmForWake(
    IN PFDO_DATA    FdoData,
    IN BOOLEAN      DeviceStateChange
    )
/*++

Routine Description:

    Sends a wait-wake to the bus driver.  If the device is already armed
    for wakeup, this routine returns TRUE.

Arguments:

    FdoData - Points to device extension

    DeviceStateChange - TRUE if this function is being called by PnP. FALSE if
                        it is coming in via WMI or due to a rearm attempt.

Return Value:

    TRUE of FALSE

--*/
{
    NTSTATUS     status;
    WAKESTATE    oldWakeState;
    POWER_STATE  powerState;

    PAGED_CODE();

    ToasterDebugPrint(TRACE, "Entered ArmForWake\n");

    //
    // Grab disable/enable lock. The request for arm/disarm could be
    // called in the context of an user thread. So to prevent somebody
    // from suspending the thread while we are holding this PASSIVE_LEVEL
    // lock, we should call KeEnterCriticalRegion. This call disables normal
    // kernel APC from being delivered, which is used in suspending a thread.
    // This step is required to prevent possible deadlocks.
    //
    KeEnterCriticalRegion();
    KeWaitForSingleObject( &FdoData->WakeDisableEnableLock,
                           Executive,
                           KernelMode,
                           FALSE,
                           NULL );

    //
    // If this is coming in response to a PnP state change, allow current and
    // future attempts to arm. Until now, all wait-wake arm attempts would be
    // failed.
    //
    if (DeviceStateChange) {

        FdoData->AllowWakeArming = TRUE;
    }

    //
    // Only arm if we aren't removed/stopped/etc, and the registry allows it.
    //
    if (!(FdoData->AllowWakeArming && ToasterGetWaitWakeEnableState(FdoData))) {

        //
        // Wake not enabled
        //
        status = STATUS_UNSUCCESSFUL;

    } else {

        oldWakeState = InterlockedCompareExchange((PULONG) &FdoData->WakeState,
                                                   WAKESTATE_WAITING,
                                                   WAKESTATE_DISARMED );

        if (oldWakeState != WAKESTATE_DISARMED) {

            //
            // Already armed or in the process of arming/rearming.
            //
            status = STATUS_SUCCESS;

        } else {

            //
            // Our dispatch handler is now waiting for IRP_MN_WAIT_WAKE.
            // The state just got moved to WAKESTATE_WAITING.
            //
            KeClearEvent(&FdoData->WakeCompletedEvent);

            //
            // Since this parameter is not used, let us just set it to
            // PowerSystemUnspecified.
            //
            powerState.SystemState = PowerSystemUnspecified;

            //
            // Request the power IRP, STATUS_PENDING is success
            //
            status = PoRequestPowerIrp( FdoData->UnderlyingPDO,
                                        IRP_MN_WAIT_WAKE,
                                        powerState,
                                        ToasterWaitWakePoCompletionRoutine,
                                        (PVOID)FdoData,
                                        NULL );

            if (!NT_SUCCESS(status)) {

                FdoData->WakeState = WAKESTATE_DISARMED;

                KeSetEvent( &FdoData->WakeCompletedEvent,
                            IO_NO_INCREMENT,
                            FALSE );
            }
        }
    }

    //
    // Unlock enable/disable logic
    //
    KeSetEvent( &FdoData->WakeDisableEnableLock,
                IO_NO_INCREMENT,
                FALSE );

    KeLeaveCriticalRegion();

    return (status == STATUS_PENDING);
}
游客

返回顶部