mirror of
https://github.com/reactos/reactos.git
synced 2025-05-18 16:51:18 +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
|
IN ULONG Hand
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
FASTCALL
|
||||||
|
KiTimerListExpire(
|
||||||
|
IN PLIST_ENTRY ExpiredListHead,
|
||||||
|
IN KIRQL OldIrql
|
||||||
|
);
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
FASTCALL
|
FASTCALL
|
||||||
KiInsertTreeTimer(
|
KiInsertTreeTimer(
|
||||||
|
|
|
@ -1099,6 +1099,37 @@ KiCheckAlertability(IN PKTHREAD Thread,
|
||||||
return STATUS_WAIT_0;
|
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.
|
// Called by Wait and Queue code to insert a timer for dispatching.
|
||||||
// Also called by KeSetTimerEx to insert a timer from the caller.
|
// 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.
|
// Called from Unlink and Queue Insert Code.
|
||||||
// Also called by timer code when canceling an inserted timer.
|
// Also called by timer code when canceling an inserted timer.
|
||||||
|
|
|
@ -40,7 +40,6 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
||||||
PKSPIN_LOCK_QUEUE LockQueue;
|
PKSPIN_LOCK_QUEUE LockQueue;
|
||||||
LIST_ENTRY TempList, TempList2;
|
LIST_ENTRY TempList, TempList2;
|
||||||
ULONG Hand, i;
|
ULONG Hand, i;
|
||||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
ASSERT((NewTime->HighPart & 0xF0000000) == 0);
|
ASSERT((NewTime->HighPart & 0xF0000000) == 0);
|
||||||
|
@ -57,10 +56,10 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
||||||
/* Query the system time now */
|
/* Query the system time now */
|
||||||
KeQuerySystemTime(OldTime);
|
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.LowPart = NewTime->LowPart;
|
||||||
SharedUserData->SystemTime.High1Time = NewTime->HighPart;
|
SharedUserData->SystemTime.High1Time = NewTime->HighPart;
|
||||||
SharedUserData->SystemTime.High2Time = NewTime->HighPart;
|
|
||||||
|
|
||||||
/* Check if this was for the HAL and set the RTC time */
|
/* Check if this was for the HAL and set the RTC time */
|
||||||
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
|
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
|
||||||
|
@ -98,16 +97,7 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
||||||
if (Timer->Header.Absolute)
|
if (Timer->Header.Absolute)
|
||||||
{
|
{
|
||||||
/* Remove it from the timer list */
|
/* Remove it from the timer list */
|
||||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
KiRemoveEntryTimer(Timer);
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert it into our temporary list */
|
/* Insert it into our temporary list */
|
||||||
InsertTailList(&TempList, &Timer->TimerListEntry);
|
InsertTailList(&TempList, &Timer->TimerListEntry);
|
||||||
|
@ -138,16 +128,7 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
||||||
if (KiInsertTimerTable(Timer, Hand))
|
if (KiInsertTimerTable(Timer, Hand))
|
||||||
{
|
{
|
||||||
/* Remove it from the timer list */
|
/* Remove it from the timer list */
|
||||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
KiRemoveEntryTimer(Timer);
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert it into our temporary list */
|
/* Insert it into our temporary list */
|
||||||
InsertTailList(&TempList2, &Timer->TimerListEntry);
|
InsertTailList(&TempList2, &Timer->TimerListEntry);
|
||||||
|
@ -157,8 +138,8 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
||||||
KiReleaseTimerLock(LockQueue);
|
KiReleaseTimerLock(LockQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Process expired timers! */
|
/* Process expired timers. This releases the dispatcher lock. */
|
||||||
KiReleaseDispatcherLock(OldIrql);
|
KiTimerListExpire(&TempList2, OldIrql);
|
||||||
|
|
||||||
/* Revert affinity */
|
/* Revert affinity */
|
||||||
KeRevertToUserAffinityThread();
|
KeRevertToUserAffinityThread();
|
||||||
|
|
|
@ -86,7 +86,6 @@ KiTimerExpiration(IN PKDPC Dpc,
|
||||||
LONG Limit, Index, i;
|
LONG Limit, Index, i;
|
||||||
ULONG Timers, ActiveTimers, DpcCalls;
|
ULONG Timers, ActiveTimers, DpcCalls;
|
||||||
PLIST_ENTRY ListHead, NextEntry;
|
PLIST_ENTRY ListHead, NextEntry;
|
||||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
PKTIMER Timer;
|
PKTIMER Timer;
|
||||||
PKDPC TimerDpc;
|
PKDPC TimerDpc;
|
||||||
|
@ -147,16 +146,7 @@ KiTimerExpiration(IN PKDPC Dpc,
|
||||||
{
|
{
|
||||||
/* It's expired, remove it */
|
/* It's expired, remove it */
|
||||||
ActiveTimers--;
|
ActiveTimers--;
|
||||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
KiRemoveEntryTimer(Timer);
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make it non-inserted, unlock it, and signal it */
|
/* Make it non-inserted, unlock it, and signal it */
|
||||||
Timer->Header.Inserted = FALSE;
|
Timer->Header.Inserted = FALSE;
|
||||||
|
@ -192,6 +182,7 @@ KiTimerExpiration(IN PKDPC Dpc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we have a DPC */
|
/* Check if we have a DPC */
|
||||||
|
#ifndef CONFIG_SMP
|
||||||
if (TimerDpc)
|
if (TimerDpc)
|
||||||
{
|
{
|
||||||
/* Setup the DPC Entry */
|
/* Setup the DPC Entry */
|
||||||
|
@ -199,7 +190,11 @@ KiTimerExpiration(IN PKDPC Dpc,
|
||||||
DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
|
DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
|
||||||
DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
|
DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
|
||||||
DpcCalls++;
|
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 */
|
/* Check if we're done processing */
|
||||||
if (!(ActiveTimers) || !(Timers))
|
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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
KiQuantumEnd(VOID)
|
KiQuantumEnd(VOID)
|
||||||
|
|
|
@ -29,71 +29,29 @@ KiInsertTreeTimer(IN PKTIMER Timer,
|
||||||
BOOLEAN Inserted = FALSE;
|
BOOLEAN Inserted = FALSE;
|
||||||
ULONG Hand = 0;
|
ULONG Hand = 0;
|
||||||
PKSPIN_LOCK_QUEUE LockQueue;
|
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);
|
DPRINT("KiInsertTreeTimer(): Timer %p, Interval: %I64d\n", Timer, Interval.QuadPart);
|
||||||
|
|
||||||
/* Convert to relative time if needed */
|
/* Setup the timer's due time */
|
||||||
Timer->Header.Absolute = FALSE;
|
if (KiComputeDueTime(Timer, Interval, &Hand))
|
||||||
if (Interval.HighPart >= 0)
|
|
||||||
{
|
{
|
||||||
/* Get System Time */
|
/* Acquire the lock */
|
||||||
KeQuerySystemTime(&SystemTime);
|
LockQueue = KiAcquireTimerLock(Hand);
|
||||||
|
|
||||||
/* Do the conversion */
|
/* Insert the timer */
|
||||||
DifferenceTime.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
|
if (KiInsertTimerTable(Timer, Hand))
|
||||||
|
|
||||||
/* Make sure it hasn't already expired */
|
|
||||||
Timer->Header.Absolute = TRUE;
|
|
||||||
if (DifferenceTime.HighPart >= 0)
|
|
||||||
{
|
{
|
||||||
/* Cancel everything */
|
/* It was already there, remove it */
|
||||||
Timer->Header.SignalState = TRUE;
|
KiRemoveEntryTimer(Timer);
|
||||||
Timer->Header.Hand = 0;
|
Timer->Header.Inserted = FALSE;
|
||||||
Timer->DueTime.QuadPart = 0;
|
}
|
||||||
return FALSE;
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we're now inserted */
|
||||||
|
Inserted = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the time as Absolute */
|
/* Release the lock */
|
||||||
Interval = DifferenceTime;
|
KiReleaseTimerLock(LockQueue);
|
||||||
}
|
|
||||||
|
|
||||||
/* 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))
|
|
||||||
{
|
|
||||||
/* Get the entry and check if it's empty */
|
|
||||||
TimerEntry = &KiTimerTableListHead[Hand];
|
|
||||||
if (IsListEmpty(&TimerEntry->Entry))
|
|
||||||
{
|
|
||||||
/* Clear the time then */
|
|
||||||
TimerEntry->Time.HighPart = 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Otherwise, we're now inserted */
|
|
||||||
Inserted = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the lock and return insert status */
|
/* Release the lock and return insert status */
|
||||||
|
@ -110,7 +68,6 @@ KiInsertTimerTable(IN PKTIMER Timer,
|
||||||
BOOLEAN Expired = FALSE;
|
BOOLEAN Expired = FALSE;
|
||||||
PLIST_ENTRY ListHead, NextEntry;
|
PLIST_ENTRY ListHead, NextEntry;
|
||||||
PKTIMER CurrentTimer;
|
PKTIMER CurrentTimer;
|
||||||
|
|
||||||
DPRINT("KiInsertTimerTable(): Timer %p, Hand: %d\n", Timer, Hand);
|
DPRINT("KiInsertTimerTable(): Timer %p, Hand: %d\n", Timer, Hand);
|
||||||
|
|
||||||
/* Check if the period is zero */
|
/* Check if the period is zero */
|
||||||
|
@ -160,7 +117,6 @@ KiSignalTimer(IN PKTIMER Timer)
|
||||||
PKDPC Dpc = Timer->Dpc;
|
PKDPC Dpc = Timer->Dpc;
|
||||||
ULONG Period = Timer->Period;
|
ULONG Period = Timer->Period;
|
||||||
LARGE_INTEGER Interval, SystemTime;
|
LARGE_INTEGER Interval, SystemTime;
|
||||||
|
|
||||||
DPRINT("KiSignalTimer(): Timer %p\n", Timer);
|
DPRINT("KiSignalTimer(): Timer %p\n", Timer);
|
||||||
|
|
||||||
/* Set default values */
|
/* Set default values */
|
||||||
|
@ -212,22 +168,11 @@ KiCompleteTimer(IN PKTIMER Timer,
|
||||||
IN PKSPIN_LOCK_QUEUE LockQueue)
|
IN PKSPIN_LOCK_QUEUE LockQueue)
|
||||||
{
|
{
|
||||||
LIST_ENTRY ListHead;
|
LIST_ENTRY ListHead;
|
||||||
PKTIMER_TABLE_ENTRY TimerEntry;
|
|
||||||
BOOLEAN RequestInterrupt = FALSE;
|
BOOLEAN RequestInterrupt = FALSE;
|
||||||
|
|
||||||
DPRINT("KiCompleteTimer(): Timer %p, LockQueue: %p\n", Timer, LockQueue);
|
DPRINT("KiCompleteTimer(): Timer %p, LockQueue: %p\n", Timer, LockQueue);
|
||||||
|
|
||||||
/* Remove it from the timer list */
|
/* Remove it from the timer list */
|
||||||
if (RemoveEntryList(&Timer->TimerListEntry))
|
KiRemoveEntryTimer(Timer);
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link the timer list to our stack */
|
/* Link the timer list to our stack */
|
||||||
ListHead.Flink = &Timer->TimerListEntry;
|
ListHead.Flink = &Timer->TimerListEntry;
|
||||||
|
@ -264,7 +209,6 @@ KeCancelTimer(IN OUT PKTIMER Timer)
|
||||||
BOOLEAN Inserted;
|
BOOLEAN Inserted;
|
||||||
ASSERT_TIMER(Timer);
|
ASSERT_TIMER(Timer);
|
||||||
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||||
|
|
||||||
DPRINT("KeCancelTimer(): Timer %p\n", Timer);
|
DPRINT("KeCancelTimer(): Timer %p\n", Timer);
|
||||||
|
|
||||||
/* Lock the Database and Raise IRQL */
|
/* Lock the Database and Raise IRQL */
|
||||||
|
@ -301,7 +245,8 @@ KeInitializeTimerEx(OUT PKTIMER Timer,
|
||||||
IN TIMER_TYPE Type)
|
IN TIMER_TYPE Type)
|
||||||
{
|
{
|
||||||
DPRINT("KeInitializeTimerEx(): Timer %p, Type %s\n",
|
DPRINT("KeInitializeTimerEx(): Timer %p, Type %s\n",
|
||||||
Timer, (Type == NotificationTimer) ? "NotificationTimer" : "SynchronizationTimer");
|
Timer, (Type == NotificationTimer) ?
|
||||||
|
"NotificationTimer" : "SynchronizationTimer");
|
||||||
|
|
||||||
/* Initialize the Dispatch Header */
|
/* Initialize the Dispatch Header */
|
||||||
KeInitializeDispatcherHeader(&Timer->Header,
|
KeInitializeDispatcherHeader(&Timer->Header,
|
||||||
|
@ -352,13 +297,11 @@ KeSetTimerEx(IN OUT PKTIMER Timer,
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
BOOLEAN Inserted;
|
BOOLEAN Inserted;
|
||||||
ULONG Hand = 0;
|
ULONG Hand = 0;
|
||||||
LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
|
|
||||||
BOOLEAN RequestInterrupt = FALSE;
|
BOOLEAN RequestInterrupt = FALSE;
|
||||||
ASSERT_TIMER(Timer);
|
ASSERT_TIMER(Timer);
|
||||||
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||||
|
|
||||||
DPRINT("KeSetTimerEx(): Timer %p, DueTime %I64d, Period %d, Dpc %p\n",
|
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 */
|
/* Lock the Database and Raise IRQL */
|
||||||
OldIrql = KiAcquireDispatcherLock();
|
OldIrql = KiAcquireDispatcherLock();
|
||||||
|
@ -370,58 +313,23 @@ KeSetTimerEx(IN OUT PKTIMER Timer,
|
||||||
/* Set Default Timer Data */
|
/* Set Default Timer Data */
|
||||||
Timer->Dpc = Dpc;
|
Timer->Dpc = Dpc;
|
||||||
Timer->Period = Period;
|
Timer->Period = Period;
|
||||||
|
if (!KiComputeDueTime(Timer, DueTime, &Hand))
|
||||||
/* Convert to relative time if needed */
|
|
||||||
Timer->Header.Absolute = FALSE;
|
|
||||||
if (DueTime.HighPart >= 0)
|
|
||||||
{
|
{
|
||||||
/* Get System Time */
|
/* Signal the timer */
|
||||||
KeQuerySystemTime(&SystemTime);
|
RequestInterrupt = KiSignalTimer(Timer);
|
||||||
|
|
||||||
/* Do the conversion */
|
/* Release the dispatcher lock */
|
||||||
DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart;
|
KiReleaseDispatcherLockFromDpcLevel();
|
||||||
|
|
||||||
/* Make sure it hasn't already expired */
|
/* Check if we need to do an interrupt */
|
||||||
Timer->Header.Absolute = TRUE;
|
if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||||
if (DifferenceTime.HighPart >= 0)
|
}
|
||||||
{
|
else
|
||||||
/* Cancel everything */
|
{
|
||||||
Timer->Header.SignalState = TRUE;
|
/* Insert the timer */
|
||||||
Timer->Header.Hand = 0;
|
Timer->Header.SignalState = FALSE;
|
||||||
Timer->DueTime.QuadPart = 0;
|
KxInsertTimer(Timer, Hand);
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* Exit the dispatcher */
|
/* Exit the dispatcher */
|
||||||
KiExitDispatcher(OldIrql);
|
KiExitDispatcher(OldIrql);
|
||||||
|
|
Loading…
Reference in a new issue