mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
- Refactor timer code to share more macros (see http://www.dcl.hpi.uni-potsdam.de/research/WRK/?p=32).
- Implement expiring timers when the user changes the system time. Previously these timers would never expire if the time was set past their expiration points. - Fix a bug in KiInsertTreeTimer where, if a timer expired while we inserted it, we kept its Inserted state to TRUE. - Fix a bug where, when changing the system time, the modifications were not done in the correct order, possibly resulting in a race condition happening if someone else was checking the time simultaneously. - Tested with winetest kernel32 timer. - Thanks to Alex and Stefan. svn path=/trunk/; revision=37132
This commit is contained in:
parent
53f5e2c282
commit
42cd339c49
5 changed files with 238 additions and 163 deletions
|
@ -286,6 +286,13 @@ KiInsertTimerTable(
|
|||
IN ULONG Hand
|
||||
);
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTimerListExpire(
|
||||
IN PLIST_ENTRY ExpiredListHead,
|
||||
IN KIRQL OldIrql
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
FASTCALL
|
||||
KiInsertTreeTimer(
|
||||
|
|
|
@ -1099,6 +1099,37 @@ KiCheckAlertability(IN PKTHREAD Thread,
|
|||
return STATUS_WAIT_0;
|
||||
}
|
||||
|
||||
//
|
||||
// Called from KiCompleteTimer, KiInsertTreeTimer, KeSetSystemTime
|
||||
// to remove timer entries
|
||||
// See Windows HPI blog for more information.
|
||||
VOID
|
||||
FORCEINLINE
|
||||
KiRemoveEntryTimer(IN PKTIMER Timer)
|
||||
{
|
||||
ULONG Hand;
|
||||
PKTIMER_TABLE_ENTRY TableEntry;
|
||||
|
||||
/* Remove the timer from the timer list and check if it's empty */
|
||||
Hand = Timer->Header.Hand;
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the respective timer table entry */
|
||||
TableEntry = &KiTimerTableListHead[Hand];
|
||||
if (&TableEntry->Entry == TableEntry->Entry.Flink)
|
||||
{
|
||||
/* Set the entry to an infinite absolute time */
|
||||
TableEntry->Time.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the list entries on dbg builds so we can tell the timer is gone */
|
||||
#if DBG
|
||||
Timer->TimerListEntry.Flink = NULL;
|
||||
Timer->TimerListEntry.Blink = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Called by Wait and Queue code to insert a timer for dispatching.
|
||||
// Also called by KeSetTimerEx to insert a timer from the caller.
|
||||
|
@ -1127,6 +1158,57 @@ KxInsertTimer(IN PKTIMER Timer,
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Called by KeSetTimerEx and KiInsertTreeTimer to calculate Due Time
|
||||
// See the Windows HPI Blog for more information
|
||||
//
|
||||
BOOLEAN
|
||||
FORCEINLINE
|
||||
KiComputeDueTime(IN PKTIMER Timer,
|
||||
IN LARGE_INTEGER DueTime,
|
||||
OUT PULONG Hand)
|
||||
{
|
||||
LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
|
||||
|
||||
/* Convert to relative time if needed */
|
||||
Timer->Header.Absolute = FALSE;
|
||||
if (DueTime.HighPart >= 0)
|
||||
{
|
||||
/* Get System Time */
|
||||
KeQuerySystemTime(&SystemTime);
|
||||
|
||||
/* Do the conversion */
|
||||
DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart;
|
||||
|
||||
/* Make sure it hasn't already expired */
|
||||
Timer->Header.Absolute = TRUE;
|
||||
if (DifferenceTime.HighPart >= 0)
|
||||
{
|
||||
/* Cancel everything */
|
||||
Timer->Header.SignalState = TRUE;
|
||||
Timer->Header.Hand = 0;
|
||||
Timer->DueTime.QuadPart = 0;
|
||||
*Hand = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Set the time as Absolute */
|
||||
DueTime = DifferenceTime;
|
||||
}
|
||||
|
||||
/* Get the Interrupt Time */
|
||||
InterruptTime.QuadPart = KeQueryInterruptTime();
|
||||
|
||||
/* Recalculate due time */
|
||||
Timer->DueTime.QuadPart = InterruptTime.QuadPart - DueTime.QuadPart;
|
||||
|
||||
/* Get the handle */
|
||||
*Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
|
||||
Timer->Header.Hand = (UCHAR)*Hand;
|
||||
Timer->Header.Inserted = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Called from Unlink and Queue Insert Code.
|
||||
// Also called by timer code when canceling an inserted timer.
|
||||
|
|
|
@ -40,7 +40,6 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
|||
PKSPIN_LOCK_QUEUE LockQueue;
|
||||
LIST_ENTRY TempList, TempList2;
|
||||
ULONG Hand, i;
|
||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
||||
|
||||
/* Sanity checks */
|
||||
ASSERT((NewTime->HighPart & 0xF0000000) == 0);
|
||||
|
@ -57,10 +56,10 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
|||
/* Query the system time now */
|
||||
KeQuerySystemTime(OldTime);
|
||||
|
||||
/* Set the new system time */
|
||||
/* Set the new system time (ordering of these operations is critical) */
|
||||
SharedUserData->SystemTime.High2Time = NewTime->HighPart;
|
||||
SharedUserData->SystemTime.LowPart = NewTime->LowPart;
|
||||
SharedUserData->SystemTime.High1Time = NewTime->HighPart;
|
||||
SharedUserData->SystemTime.High2Time = NewTime->HighPart;
|
||||
|
||||
/* Check if this was for the HAL and set the RTC time */
|
||||
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
|
||||
|
@ -98,16 +97,7 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
|||
if (Timer->Header.Absolute)
|
||||
{
|
||||
/* Remove it from the timer list */
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the entry and check if it's empty */
|
||||
TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
|
||||
if (IsListEmpty(&TimerEntry->Entry))
|
||||
{
|
||||
/* Clear the time then */
|
||||
TimerEntry->Time.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
KiRemoveEntryTimer(Timer);
|
||||
|
||||
/* Insert it into our temporary list */
|
||||
InsertTailList(&TempList, &Timer->TimerListEntry);
|
||||
|
@ -138,16 +128,7 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
|||
if (KiInsertTimerTable(Timer, Hand))
|
||||
{
|
||||
/* Remove it from the timer list */
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the entry and check if it's empty */
|
||||
TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
|
||||
if (IsListEmpty(&TimerEntry->Entry))
|
||||
{
|
||||
/* Clear the time then */
|
||||
TimerEntry->Time.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
KiRemoveEntryTimer(Timer);
|
||||
|
||||
/* Insert it into our temporary list */
|
||||
InsertTailList(&TempList2, &Timer->TimerListEntry);
|
||||
|
@ -157,8 +138,8 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
|||
KiReleaseTimerLock(LockQueue);
|
||||
}
|
||||
|
||||
/* FIXME: Process expired timers! */
|
||||
KiReleaseDispatcherLock(OldIrql);
|
||||
/* Process expired timers. This releases the dispatcher lock. */
|
||||
KiTimerListExpire(&TempList2, OldIrql);
|
||||
|
||||
/* Revert affinity */
|
||||
KeRevertToUserAffinityThread();
|
||||
|
|
|
@ -86,7 +86,6 @@ KiTimerExpiration(IN PKDPC Dpc,
|
|||
LONG Limit, Index, i;
|
||||
ULONG Timers, ActiveTimers, DpcCalls;
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
||||
KIRQL OldIrql;
|
||||
PKTIMER Timer;
|
||||
PKDPC TimerDpc;
|
||||
|
@ -147,16 +146,7 @@ KiTimerExpiration(IN PKDPC Dpc,
|
|||
{
|
||||
/* It's expired, remove it */
|
||||
ActiveTimers--;
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the entry and check if it's empty */
|
||||
TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
|
||||
if (IsListEmpty(&TimerEntry->Entry))
|
||||
{
|
||||
/* Clear the time then */
|
||||
TimerEntry->Time.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
KiRemoveEntryTimer(Timer);
|
||||
|
||||
/* Make it non-inserted, unlock it, and signal it */
|
||||
Timer->Header.Inserted = FALSE;
|
||||
|
@ -192,6 +182,7 @@ KiTimerExpiration(IN PKDPC Dpc,
|
|||
}
|
||||
|
||||
/* Check if we have a DPC */
|
||||
#ifndef CONFIG_SMP
|
||||
if (TimerDpc)
|
||||
{
|
||||
/* Setup the DPC Entry */
|
||||
|
@ -199,7 +190,11 @@ KiTimerExpiration(IN PKDPC Dpc,
|
|||
DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
|
||||
DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
|
||||
DpcCalls++;
|
||||
ASSERT(DpcCalls < MAX_TIMER_DPCS);
|
||||
}
|
||||
#else
|
||||
#error MP Case: Need to check the DPC target CPU so see if we can piggyback
|
||||
#endif
|
||||
|
||||
/* Check if we're done processing */
|
||||
if (!(ActiveTimers) || !(Timers))
|
||||
|
@ -303,6 +298,108 @@ KiTimerExpiration(IN PKDPC Dpc,
|
|||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTimerListExpire(IN PLIST_ENTRY ExpiredListHead,
|
||||
IN KIRQL OldIrql)
|
||||
{
|
||||
ULARGE_INTEGER SystemTime;
|
||||
LARGE_INTEGER Interval;
|
||||
LONG i;
|
||||
ULONG DpcCalls = 0;
|
||||
PKTIMER Timer;
|
||||
PKDPC TimerDpc;
|
||||
ULONG Period;
|
||||
DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS];
|
||||
|
||||
/* Query system */
|
||||
KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
|
||||
|
||||
/* Loop expired list */
|
||||
while (ExpiredListHead->Flink != ExpiredListHead)
|
||||
{
|
||||
/* Get the current timer */
|
||||
Timer = CONTAINING_RECORD(ExpiredListHead->Flink, KTIMER, TimerListEntry);
|
||||
|
||||
/* Remove it */
|
||||
RemoveEntryList(&Timer->TimerListEntry);
|
||||
|
||||
/* Not inserted */
|
||||
Timer->Header.Inserted = FALSE;
|
||||
|
||||
/* Signal it */
|
||||
Timer->Header.SignalState = 1;
|
||||
|
||||
/* Get the DPC and period */
|
||||
TimerDpc = Timer->Dpc;
|
||||
Period = Timer->Period;
|
||||
|
||||
/* Check if there's any waiters */
|
||||
if (!IsListEmpty(&Timer->Header.WaitListHead))
|
||||
{
|
||||
/* Check the type of event */
|
||||
if (Timer->Header.Type == TimerNotificationObject)
|
||||
{
|
||||
/* Unwait the thread */
|
||||
KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise unwait the thread and signal the timer */
|
||||
KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have a period */
|
||||
if (Period)
|
||||
{
|
||||
/* Calculate the interval and insert the timer */
|
||||
Interval.QuadPart = Int32x32To64(Period, -10000);
|
||||
while (!KiInsertTreeTimer(Timer, Interval));
|
||||
}
|
||||
|
||||
/* Check if we have a DPC */
|
||||
#ifndef CONFIG_SMP
|
||||
if (TimerDpc)
|
||||
{
|
||||
/* Setup the DPC Entry */
|
||||
DpcEntry[DpcCalls].Dpc = TimerDpc;
|
||||
DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
|
||||
DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
|
||||
DpcCalls++;
|
||||
ASSERT(DpcCalls < MAX_TIMER_DPCS);
|
||||
}
|
||||
#else
|
||||
#error MP Case: Need to check the DPC target CPU so see if we can piggyback
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if we still have DPC entries */
|
||||
if (DpcCalls)
|
||||
{
|
||||
/* Release the dispatcher while doing DPCs */
|
||||
KiReleaseDispatcherLock(DISPATCH_LEVEL);
|
||||
|
||||
/* Start looping all DPC Entries */
|
||||
for (i = 0; DpcCalls; DpcCalls--, i++)
|
||||
{
|
||||
/* Call the DPC */
|
||||
DpcEntry[i].Routine(DpcEntry[i].Dpc,
|
||||
DpcEntry[i].Context,
|
||||
UlongToPtr(SystemTime.LowPart),
|
||||
UlongToPtr(SystemTime.HighPart));
|
||||
}
|
||||
|
||||
/* Lower IRQL */
|
||||
KeLowerIrql(OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unlock the dispatcher */
|
||||
KiReleaseDispatcherLock(OldIrql);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiQuantumEnd(VOID)
|
||||
|
|
|
@ -29,71 +29,29 @@ KiInsertTreeTimer(IN PKTIMER Timer,
|
|||
BOOLEAN Inserted = FALSE;
|
||||
ULONG Hand = 0;
|
||||
PKSPIN_LOCK_QUEUE LockQueue;
|
||||
LONGLONG DueTime;
|
||||
LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
|
||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
||||
|
||||
DPRINT("KiInsertTreeTimer(): Timer %p, Interval: %I64d\n", Timer, Interval.QuadPart);
|
||||
|
||||
/* Convert to relative time if needed */
|
||||
Timer->Header.Absolute = FALSE;
|
||||
if (Interval.HighPart >= 0)
|
||||
/* Setup the timer's due time */
|
||||
if (KiComputeDueTime(Timer, Interval, &Hand))
|
||||
{
|
||||
/* Get System Time */
|
||||
KeQuerySystemTime(&SystemTime);
|
||||
/* Acquire the lock */
|
||||
LockQueue = KiAcquireTimerLock(Hand);
|
||||
|
||||
/* Do the conversion */
|
||||
DifferenceTime.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
|
||||
|
||||
/* Make sure it hasn't already expired */
|
||||
Timer->Header.Absolute = TRUE;
|
||||
if (DifferenceTime.HighPart >= 0)
|
||||
/* Insert the timer */
|
||||
if (KiInsertTimerTable(Timer, Hand))
|
||||
{
|
||||
/* Cancel everything */
|
||||
Timer->Header.SignalState = TRUE;
|
||||
Timer->Header.Hand = 0;
|
||||
Timer->DueTime.QuadPart = 0;
|
||||
return FALSE;
|
||||
/* It was already there, remove it */
|
||||
KiRemoveEntryTimer(Timer);
|
||||
Timer->Header.Inserted = FALSE;
|
||||
}
|
||||
|
||||
/* Set the time as Absolute */
|
||||
Interval = DifferenceTime;
|
||||
}
|
||||
|
||||
/* Get the Interrupt Time */
|
||||
InterruptTime.QuadPart = KeQueryInterruptTime();
|
||||
|
||||
/* Recalculate due time */
|
||||
DueTime = InterruptTime.QuadPart - Interval.QuadPart;
|
||||
Timer->DueTime.QuadPart = DueTime;
|
||||
|
||||
/* Get the handle */
|
||||
Hand = KiComputeTimerTableIndex(DueTime);
|
||||
Timer->Header.Hand = (UCHAR)Hand;
|
||||
Timer->Header.Inserted = TRUE;
|
||||
|
||||
/* Acquire the lock */
|
||||
LockQueue = KiAcquireTimerLock(Hand);
|
||||
|
||||
/* Insert the timer */
|
||||
if (KiInsertTimerTable(Timer, Hand))
|
||||
{
|
||||
/* It was already there, remove it */
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
else
|
||||
{
|
||||
/* Get the entry and check if it's empty */
|
||||
TimerEntry = &KiTimerTableListHead[Hand];
|
||||
if (IsListEmpty(&TimerEntry->Entry))
|
||||
{
|
||||
/* Clear the time then */
|
||||
TimerEntry->Time.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
/* Otherwise, we're now inserted */
|
||||
Inserted = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, we're now inserted */
|
||||
Inserted = TRUE;
|
||||
|
||||
/* Release the lock */
|
||||
KiReleaseTimerLock(LockQueue);
|
||||
}
|
||||
|
||||
/* Release the lock and return insert status */
|
||||
|
@ -110,7 +68,6 @@ KiInsertTimerTable(IN PKTIMER Timer,
|
|||
BOOLEAN Expired = FALSE;
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
PKTIMER CurrentTimer;
|
||||
|
||||
DPRINT("KiInsertTimerTable(): Timer %p, Hand: %d\n", Timer, Hand);
|
||||
|
||||
/* Check if the period is zero */
|
||||
|
@ -160,7 +117,6 @@ KiSignalTimer(IN PKTIMER Timer)
|
|||
PKDPC Dpc = Timer->Dpc;
|
||||
ULONG Period = Timer->Period;
|
||||
LARGE_INTEGER Interval, SystemTime;
|
||||
|
||||
DPRINT("KiSignalTimer(): Timer %p\n", Timer);
|
||||
|
||||
/* Set default values */
|
||||
|
@ -212,22 +168,11 @@ KiCompleteTimer(IN PKTIMER Timer,
|
|||
IN PKSPIN_LOCK_QUEUE LockQueue)
|
||||
{
|
||||
LIST_ENTRY ListHead;
|
||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
||||
BOOLEAN RequestInterrupt = FALSE;
|
||||
|
||||
DPRINT("KiCompleteTimer(): Timer %p, LockQueue: %p\n", Timer, LockQueue);
|
||||
|
||||
/* Remove it from the timer list */
|
||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
||||
{
|
||||
/* Get the entry and check if it's empty */
|
||||
TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
|
||||
if (IsListEmpty(&TimerEntry->Entry))
|
||||
{
|
||||
/* Clear the time then */
|
||||
TimerEntry->Time.HighPart = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
KiRemoveEntryTimer(Timer);
|
||||
|
||||
/* Link the timer list to our stack */
|
||||
ListHead.Flink = &Timer->TimerListEntry;
|
||||
|
@ -264,7 +209,6 @@ KeCancelTimer(IN OUT PKTIMER Timer)
|
|||
BOOLEAN Inserted;
|
||||
ASSERT_TIMER(Timer);
|
||||
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||
|
||||
DPRINT("KeCancelTimer(): Timer %p\n", Timer);
|
||||
|
||||
/* Lock the Database and Raise IRQL */
|
||||
|
@ -301,7 +245,8 @@ KeInitializeTimerEx(OUT PKTIMER Timer,
|
|||
IN TIMER_TYPE Type)
|
||||
{
|
||||
DPRINT("KeInitializeTimerEx(): Timer %p, Type %s\n",
|
||||
Timer, (Type == NotificationTimer) ? "NotificationTimer" : "SynchronizationTimer");
|
||||
Timer, (Type == NotificationTimer) ?
|
||||
"NotificationTimer" : "SynchronizationTimer");
|
||||
|
||||
/* Initialize the Dispatch Header */
|
||||
KeInitializeDispatcherHeader(&Timer->Header,
|
||||
|
@ -352,13 +297,11 @@ KeSetTimerEx(IN OUT PKTIMER Timer,
|
|||
KIRQL OldIrql;
|
||||
BOOLEAN Inserted;
|
||||
ULONG Hand = 0;
|
||||
LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
|
||||
BOOLEAN RequestInterrupt = FALSE;
|
||||
ASSERT_TIMER(Timer);
|
||||
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||
|
||||
DPRINT("KeSetTimerEx(): Timer %p, DueTime %I64d, Period %d, Dpc %p\n",
|
||||
Timer, DueTime.QuadPart, Period, Dpc);
|
||||
Timer, DueTime.QuadPart, Period, Dpc);
|
||||
|
||||
/* Lock the Database and Raise IRQL */
|
||||
OldIrql = KiAcquireDispatcherLock();
|
||||
|
@ -370,59 +313,24 @@ KeSetTimerEx(IN OUT PKTIMER Timer,
|
|||
/* Set Default Timer Data */
|
||||
Timer->Dpc = Dpc;
|
||||
Timer->Period = Period;
|
||||
|
||||
/* Convert to relative time if needed */
|
||||
Timer->Header.Absolute = FALSE;
|
||||
if (DueTime.HighPart >= 0)
|
||||
if (!KiComputeDueTime(Timer, DueTime, &Hand))
|
||||
{
|
||||
/* Get System Time */
|
||||
KeQuerySystemTime(&SystemTime);
|
||||
|
||||
/* Do the conversion */
|
||||
DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart;
|
||||
|
||||
/* Make sure it hasn't already expired */
|
||||
Timer->Header.Absolute = TRUE;
|
||||
if (DifferenceTime.HighPart >= 0)
|
||||
{
|
||||
/* Cancel everything */
|
||||
Timer->Header.SignalState = TRUE;
|
||||
Timer->Header.Hand = 0;
|
||||
Timer->DueTime.QuadPart = 0;
|
||||
|
||||
/* Signal the timer */
|
||||
RequestInterrupt = KiSignalTimer(Timer);
|
||||
|
||||
/* Release the dispatcher lock */
|
||||
KiReleaseDispatcherLockFromDpcLevel();
|
||||
|
||||
/* Check if we need to do an interrupt */
|
||||
if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
|
||||
/* Exit the dispatcher and return the old state */
|
||||
KiExitDispatcher(OldIrql);
|
||||
return Inserted;
|
||||
}
|
||||
|
||||
/* Set the time as Absolute */
|
||||
DueTime = DifferenceTime;
|
||||
/* Signal the timer */
|
||||
RequestInterrupt = KiSignalTimer(Timer);
|
||||
|
||||
/* Release the dispatcher lock */
|
||||
KiReleaseDispatcherLockFromDpcLevel();
|
||||
|
||||
/* Check if we need to do an interrupt */
|
||||
if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
|
||||
/* Get the Interrupt Time */
|
||||
InterruptTime.QuadPart = KeQueryInterruptTime();
|
||||
|
||||
/* Recalculate due time */
|
||||
Timer->DueTime.QuadPart = InterruptTime.QuadPart - DueTime.QuadPart;
|
||||
|
||||
/* Get the handle */
|
||||
Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
|
||||
Timer->Header.Hand = (UCHAR)Hand;
|
||||
Timer->Header.Inserted = TRUE;
|
||||
|
||||
/* Insert the timer */
|
||||
Timer->Header.SignalState = FALSE;
|
||||
KxInsertTimer(Timer, Hand);
|
||||
|
||||
else
|
||||
{
|
||||
/* Insert the timer */
|
||||
Timer->Header.SignalState = FALSE;
|
||||
KxInsertTimer(Timer, Hand);
|
||||
}
|
||||
|
||||
/* Exit the dispatcher */
|
||||
KiExitDispatcher(OldIrql);
|
||||
|
||||
|
|
Loading…
Reference in a new issue