/*++

Copyright (c) Microsoft. All rights reserved.

Module Name:

    FxWatchDog.hpp

Abstract:

    This module implements the watchdog utility class for the power and power
    policy state machines

Author:



Environment:

    Both kernel and user mode

Revision History:

--*/

#ifndef __FX_WATCHDOG__
#define __FX_WATCHDOG__

struct FxWatchdog {
    FxWatchdog(
        __in FxPkgPnp* PkgPnp
        )
    {
        m_PkgPnp = PkgPnp;
    }

    VOID
    StartTimer(
        __in ULONG State
        )
    {
        LARGE_INTEGER time;
        NTSTATUS status;

        if (State & WdfDevStateNP) {
            //
            // This is a non-pageable state.  So we set the timer watchdog.
            // If it fires, it means that the driver stalled, probably due
            // to a page fault, which means that the whole machine is wedged.
            // We will then attempt to put the failure in the trace log
            // and bring the machine down, hopefully getting the reason we
            // stopped responding into the crashdump.  (This will probably only work
            // if the machine is hibernating.)
            //
            // If the state function returns, then we'll cancel the timer
            // and no love will be lost.
            //
            status = m_Timer.Initialize(this, _WatchdogDpc, 0);

            //
            // This code is not used in UM. Hence we can assert and assume that
            // timer start will always be successful.
            //
            WDF_VERIFY_KM_ONLY_CODE();

            FX_ASSERT_AND_ASSUME_FOR_PREFAST(NT_SUCCESS(status));

            m_CallingThread = Mx::MxGetCurrentThread();

            if (m_PkgPnp->m_SharedPower.m_ExtendWatchDogTimer) {
                //
                // 24 hours:
                //  60 = to minutes
                //  60 = to hours
                //  24 = number of hours
                //
                time.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60 * 60 * 24);
            }
            else {
                //
                // 10 minutes from now (same as the Vista timeout)
                //
                time.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60 * 10);
            }

            m_Timer.Start(time);
        }
    }

    VOID
    CancelTimer(
        __in ULONG State
        )
    {
        if (State & WdfDevStateNP) {
            //
            // The state was successfully handled without the timer expiring.
            // We don't care about the return code in this case.
            //
            (void) m_Timer.Stop();
        }
    }

    static
    MdDeferredRoutineType
    _WatchdogDpc;

    MxTimer m_Timer;

    FxPkgPnp* m_PkgPnp;

    MxThread m_CallingThread;
};

#endif // __FX_WATCHDOG__