mirror of
https://github.com/reactos/reactos.git
synced 2025-03-10 18:24:02 +00:00
296 lines
6.8 KiB
C
296 lines
6.8 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
ModuleName:
|
|
|
|
MxTimerKm.h
|
|
|
|
Abstract:
|
|
|
|
Kernel mode implementation of timer defined in
|
|
MxTimer.h
|
|
|
|
Author:
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#pragma once
|
|
|
|
#define TolerableDelayUnlimited ((ULONG)-1)
|
|
|
|
typedef
|
|
BOOLEAN
|
|
(STDCALL *PFN_KE_SET_COALESCABLE_TIMER) (
|
|
__inout PKTIMER Timer,
|
|
__in LARGE_INTEGER DueTime,
|
|
__in ULONG Period,
|
|
__in ULONG TolerableDelay,
|
|
__in_opt PKDPC Dpc
|
|
);
|
|
|
|
typedef struct _MdTimer {
|
|
|
|
|
|
//
|
|
// The timer period
|
|
//
|
|
LONG m_Period;
|
|
|
|
//
|
|
// Tracks whether the ex timer is being used
|
|
//
|
|
BOOLEAN m_IsExtTimer;
|
|
|
|
// #pragma warning(push)
|
|
// #pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union
|
|
|
|
union {
|
|
struct {
|
|
//
|
|
// Callback function to be invoked upon timer expiration
|
|
//
|
|
MdDeferredRoutine m_TimerCallback;
|
|
KTIMER KernelTimer;
|
|
KDPC TimerDpc;
|
|
};
|
|
|
|
struct {
|
|
//
|
|
// Callback function to be invoked upon timer expiration
|
|
//
|
|
MdExtCallback m_ExTimerCallback;
|
|
PEX_TIMER m_KernelExTimer;
|
|
};
|
|
};
|
|
|
|
// #pragma warning(pop)
|
|
|
|
//
|
|
// Context to be passed in to the callback function
|
|
//
|
|
PVOID m_TimerContext;
|
|
|
|
} MdTimer;
|
|
|
|
#include "mxtimer.h"
|
|
|
|
MxTimer::MxTimer(
|
|
VOID
|
|
)
|
|
{
|
|
m_Timer.m_TimerContext = NULL;
|
|
m_Timer.m_TimerCallback = NULL;
|
|
m_Timer.m_Period = 0;
|
|
m_Timer.m_KernelExTimer = NULL;
|
|
}
|
|
|
|
MxTimer::~MxTimer(
|
|
VOID
|
|
)
|
|
{
|
|
// __REACTOS__ Ex timers are not supported
|
|
// BOOLEAN wasCancelled;
|
|
|
|
// if (m_Timer.m_IsExtTimer &&
|
|
// m_Timer.m_KernelExTimer) {
|
|
// wasCancelled = ExDeleteTimer(m_Timer.m_KernelExTimer,
|
|
// TRUE, // Cancel if pending. We don't expect
|
|
// // it to be pending though
|
|
// FALSE,// Wait
|
|
// NULL);
|
|
// //
|
|
// // Timer should not have been pending
|
|
// //
|
|
// ASSERT(wasCancelled == FALSE);
|
|
// m_Timer.m_KernelExTimer = NULL;
|
|
// }
|
|
}
|
|
|
|
NTSTATUS
|
|
#ifdef _MSC_VER
|
|
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "_Must_inspect_result_ not needed in kernel mode as the function always succeeds");
|
|
#endif
|
|
MxTimer::Initialize(
|
|
__in_opt PVOID TimerContext,
|
|
__in MdDeferredRoutine TimerCallback,
|
|
__in LONG Period
|
|
)
|
|
{
|
|
m_Timer.m_TimerContext = TimerContext;
|
|
m_Timer.m_TimerCallback = TimerCallback;
|
|
m_Timer.m_Period = Period;
|
|
|
|
KeInitializeTimerEx(&(m_Timer.KernelTimer), NotificationTimer);
|
|
KeInitializeDpc(&(m_Timer.TimerDpc), // Timer DPC
|
|
m_Timer.m_TimerCallback, // DeferredRoutine
|
|
m_Timer.m_TimerContext); // DeferredContext
|
|
|
|
m_Timer.m_IsExtTimer = FALSE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
MxTimer::InitializeEx(
|
|
__in_opt PVOID TimerContext,
|
|
__in MdExtCallback TimerCallback,
|
|
__in LONG Period,
|
|
__in ULONG TolerableDelay,
|
|
__in BOOLEAN UseHighResolutionTimer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an Ex timer. By invoking this routine instead of
|
|
Initialize, the client is implicitly declaring that it wants
|
|
to use the new timers
|
|
|
|
Arguments:
|
|
|
|
TimerContext - Context to be passed back with the cllback
|
|
TimerCallback - Callback to be invoked when the timer fires
|
|
Period - Period in ms
|
|
TolerableDelay - Tolerable delay in ms
|
|
UseHighResolutionTimer- Indicates whether to use the high
|
|
resolution timers
|
|
|
|
Returns:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
// NTSTATUS status;
|
|
// ULONG attributes = 0;
|
|
|
|
// m_Timer.m_TimerContext = TimerContext;
|
|
// m_Timer.m_ExTimerCallback = TimerCallback;
|
|
// m_Timer.m_Period = Period;
|
|
|
|
// if (TolerableDelay != 0) {
|
|
|
|
// attributes |= EX_TIMER_NO_WAKE;
|
|
|
|
// } else if (UseHighResolutionTimer) {
|
|
|
|
// attributes |= EX_TIMER_HIGH_RESOLUTION;
|
|
// }
|
|
|
|
// m_Timer.m_KernelExTimer = ExAllocateTimer(m_Timer.m_ExTimerCallback,
|
|
// TimerContext,
|
|
// attributes);
|
|
// if (m_Timer.m_KernelExTimer) {
|
|
|
|
// status = STATUS_SUCCESS;
|
|
|
|
// } else {
|
|
|
|
// status = STATUS_INSUFFICIENT_RESOURCES;
|
|
// }
|
|
|
|
// m_Timer.m_IsExtTimer = TRUE;
|
|
|
|
// return status;
|
|
return STATUS_NOT_IMPLEMENTED; // __REACTOS__ Ex timers are not supported
|
|
}
|
|
|
|
|
|
__inline
|
|
BOOLEAN
|
|
MxTimer::StartWithReturn(
|
|
__in LARGE_INTEGER DueTime,
|
|
__in ULONG TolerableDelay
|
|
)
|
|
{
|
|
if (m_Timer.m_IsExtTimer) {
|
|
// __REACTOS__ Ex timers are not supported
|
|
// EXT_SET_PARAMETERS parameters;
|
|
|
|
// ExInitializeSetTimerParameters(¶meters);
|
|
|
|
// //
|
|
// // We get the delay in ms but the underlying API needs it in 100 ns
|
|
// // units. Convert tolerable delay from ms to 100 ns. However,
|
|
// // MAXULONG (TolerableDelayUnlimited) has a special meaning that the
|
|
// // system should never be woken up, so we assign the corresponding
|
|
// // special value for Ex timers
|
|
// //
|
|
// if (TolerableDelay == TolerableDelayUnlimited) {
|
|
// parameters.NoWakeTolerance = EX_TIMER_UNLIMITED_TOLERANCE;
|
|
// } else {
|
|
// parameters.NoWakeTolerance = ((LONGLONG) TolerableDelay) * 10 * 1000;
|
|
// }
|
|
|
|
// return ExSetTimer(m_Timer.m_KernelExTimer,
|
|
// DueTime.QuadPart,
|
|
// (((LONGLONG) m_Timer.m_Period) * 10 * 1000),
|
|
// ¶meters);
|
|
return FALSE;
|
|
} else {
|
|
|
|
return KeSetCoalescableTimer(&(m_Timer.KernelTimer),
|
|
DueTime,
|
|
m_Timer.m_Period,
|
|
TolerableDelay,
|
|
&(m_Timer.TimerDpc));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
MxTimer::Start(
|
|
__in LARGE_INTEGER DueTime,
|
|
__in ULONG TolerableDelay
|
|
)
|
|
{
|
|
if (m_Timer.m_IsExtTimer) {
|
|
|
|
StartWithReturn(DueTime,TolerableDelay);
|
|
|
|
} else {
|
|
KeSetCoalescableTimer(&(m_Timer.KernelTimer),
|
|
DueTime,
|
|
m_Timer.m_Period,
|
|
TolerableDelay,
|
|
&(m_Timer.TimerDpc));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
BOOLEAN
|
|
MxTimer::Stop(
|
|
VOID
|
|
)
|
|
{
|
|
BOOLEAN bRetVal;
|
|
|
|
if (m_Timer.m_IsExtTimer) {
|
|
bRetVal = FALSE;
|
|
// bRetVal = ExCancelTimer(m_Timer.m_KernelExTimer, NULL); // __REACTOS__ Ex timers are not supported
|
|
|
|
} else {
|
|
bRetVal = KeCancelTimer(&(m_Timer.KernelTimer));
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
VOID
|
|
MxTimer::FlushQueuedDpcs(
|
|
VOID
|
|
)
|
|
{
|
|
Mx::MxFlushQueuedDpcs();
|
|
}
|