Author: sginsberg
Date: Sat Nov 1 14:48:52 2008
New Revision: 37137
URL: http://svn.reactos.org/svn/reactos?rev=37137&view=rev
Log:
- Reapply 35812:
- RtlDispatchException: Call vectored exception handlers before doing anything else
- KiUserExceptionDispatcher: Call RtlDispatchException directly as it now takes care of vectored handling
- Rename RtlpExecuteVectoredExceptionHandlers to RtlCallVectoredExceptionHandlers, and fix return type
- References: "New Vectored Exception Handling in Windows XP" by Matt Pietrek
- New in this revision: Only call vectored handlers in user mode, as there is no such thing in kernel mode
Modified:
trunk/reactos/dll/ntdll/dispatch/dispatch.c
trunk/reactos/dll/ntdll/dispatch/i386/dispatch.S
trunk/reactos/lib/rtl/i386/except.c
trunk/reactos/lib/rtl/rtlp.h
trunk/reactos/lib/rtl/vectoreh.c
Modified: trunk/reactos/dll/ntdll/dispatch/dispatch.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/ntdll/dispatch/dispatc…
==============================================================================
--- trunk/reactos/dll/ntdll/dispatch/dispatch.c [iso-8859-1] (original)
+++ trunk/reactos/dll/ntdll/dispatch/dispatch.c [iso-8859-1] Sat Nov 1 14:48:52 2008
@@ -15,10 +15,6 @@
typedef NTSTATUS (NTAPI *USER_CALL)(PVOID Argument, ULONG ArgumentLength);
-EXCEPTION_DISPOSITION NTAPI
-RtlpExecuteVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
- IN PCONTEXT Context);
-
/* FUNCTIONS ****************************************************************/
/*
@@ -32,26 +28,16 @@
EXCEPTION_RECORD NestedExceptionRecord;
NTSTATUS Status;
- /* call the vectored exception handlers */
- if(RtlpExecuteVectoredExceptionHandlers(ExceptionRecord,
- Context) != ExceptionContinueExecution)
+ /* Dispatch the exception and check the result */
+ if (RtlDispatchException(ExceptionRecord, Context))
{
- goto ContinueExecution;
+ /* Continue executing */
+ Status = NtContinue(Context, FALSE);
}
else
{
- /* Dispatch the exception and check the result */
- if(RtlDispatchException(ExceptionRecord, Context))
- {
-ContinueExecution:
- /* Continue executing */
- Status = NtContinue(Context, FALSE);
- }
- else
- {
- /* Raise an exception */
- Status = NtRaiseException(ExceptionRecord, Context, FALSE);
- }
+ /* Raise an exception */
+ Status = NtRaiseException(ExceptionRecord, Context, FALSE);
}
/* Setup the Exception record */
Modified: trunk/reactos/dll/ntdll/dispatch/i386/dispatch.S
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/ntdll/dispatch/i386/di…
==============================================================================
--- trunk/reactos/dll/ntdll/dispatch/i386/dispatch.S [iso-8859-1] (original)
+++ trunk/reactos/dll/ntdll/dispatch/i386/dispatch.S [iso-8859-1] Sat Nov 1 14:48:52 2008
@@ -183,52 +183,22 @@
.globl _KiUserExceptionDispatcher@8
_KiUserExceptionDispatcher@8:
- /* clear the direct flag
- * text from bug 2279
- * if it not clear it means that if an exception occurs while
- * the direction flag is set (typically inside memmove), the
- * exception handlers will be called with the direction flag still
- * set. The Windows x86-32 and x86-64 ABI requires that the
- * direction flag be Calling memset() with a compile-time constant
- * size on both GCC and MSVC will result in inlining a "rep stosd"
- * instruction. Because of the ABI, they will assume that the
- * direction flag is clear and not emit a "cld" instruction.
- * Using memset() in an exception handler therefore will
- * corrupt memory if the exception occurred during a reverse copy
- * such as a forward overlapping memmove().
- *
- * For reliability and ease of debugging, please add "cld" to the beginning of
- * KiUserExceptionDispatcher. Note that the same will be true of x86-64 whenever
- * that happens. This does not affect continuing execution; the CONTEXT of the
- * exception has the direction flag set and will be restored upon NtContinue.
- * KiUserApcDispatcher and KiUserCallbackDispatcher need to be evaluated for this
- * issue.
- */
-
+ /* Clear direction flag */
cld
/* Save the Context and Exception Records */
mov ecx, [esp+4]
mov ebx, [esp]
- /* Call the vectored exception handler */
+ /* Dispatch the exception */
push ecx
push ebx
- call _RtlpExecuteVectoredExceptionHandlers@8
-
- /* Check for success */
- or al, al
- jnz ContinueExecution
-
- /* Dispatch the exception */
- sub esp, 8
call _RtlDispatchException@8
/* Check for success */
or al, al
jz RaiseException
-ContinueExecution:
/* Pop off the records */
pop ebx
pop ecx
Modified: trunk/reactos/lib/rtl/i386/except.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/i386/except.c?rev=…
==============================================================================
--- trunk/reactos/lib/rtl/i386/except.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/i386/except.c [iso-8859-1] Sat Nov 1 14:48:52 2008
@@ -73,6 +73,17 @@
EXCEPTION_DISPOSITION Disposition;
ULONG_PTR StackLow, StackHigh;
ULONG_PTR RegistrationFrameEnd;
+
+ /* Perform vectored exception handling if we are in user mode */
+ if (RtlpGetMode() != KernelMode)
+ {
+ /* Call any registered vectored handlers */
+ if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context))
+ {
+ /* Exception handled, continue execution */
+ return TRUE;
+ }
+ }
/* Get the current stack limits and registration frame */
RtlpGetStackLimits(&StackLow, &StackHigh);
Modified: trunk/reactos/lib/rtl/rtlp.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/rtlp.h?rev=37137&r…
==============================================================================
--- trunk/reactos/lib/rtl/rtlp.h [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/rtlp.h [iso-8859-1] Sat Nov 1 14:48:52 2008
@@ -36,6 +36,13 @@
VOID
NTAPI
RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList);
+
+BOOLEAN
+NTAPI
+RtlCallVectoredExceptionHandlers(
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PCONTEXT Context
+);
typedef struct _DISPATCHER_CONTEXT
{
Modified: trunk/reactos/lib/rtl/vectoreh.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/vectoreh.c?rev=371…
==============================================================================
--- trunk/reactos/lib/rtl/vectoreh.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/vectoreh.c [iso-8859-1] Sat Nov 1 14:48:52 2008
@@ -28,9 +28,10 @@
/* FUNCTIONS ***************************************************************/
-EXCEPTION_DISPOSITION NTAPI
-RtlpExecuteVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
- IN PCONTEXT Context)
+BOOLEAN
+NTAPI
+RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PCONTEXT Context)
{
PLIST_ENTRY CurrentEntry;
PRTL_VECTORED_EXCEPTION_HANDLER veh;
@@ -55,7 +56,7 @@
if(VectoredHandler(&ExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION)
{
- return ExceptionContinueSearch;
+ return TRUE;
}
RtlEnterCriticalSection(&RtlpVectoredExceptionLock);
@@ -63,7 +64,7 @@
RtlLeaveCriticalSection(&RtlpVectoredExceptionLock);
}
- return ExceptionContinueExecution;
+ return FALSE;
}
VOID
Author: sginsberg
Date: Sat Nov 1 13:16:17 2008
New Revision: 37133
URL: http://svn.reactos.org/svn/reactos?rev=37133&view=rev
Log:
- Implement the MP case for KiTimerExpiration and KiTimerListExpire
Modified:
trunk/reactos/ntoskrnl/ke/dpc.c
Modified: trunk/reactos/ntoskrnl/ke/dpc.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/dpc.c?rev=3713…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/dpc.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/dpc.c [iso-8859-1] Sat Nov 1 13:16:17 2008
@@ -92,6 +92,9 @@
ULONG Period;
DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS];
PKSPIN_LOCK_QUEUE LockQueue;
+#ifdef CONFIG_SMP
+ PKPRCB Prcb = KeGetCurrentPrcb();
+#endif
/* Disable interrupts */
_disable();
@@ -182,19 +185,38 @@
}
/* 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);
+#ifdef CONFIG_SMP
+ /*
+ * If the DPC is targeted to another processor,
+ * then insert it into that processor's DPC queue
+ * instead of delivering it now.
+ * If the DPC is a threaded DPC, and the current CPU
+ * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
+ * then also insert it into the DPC queue for threaded delivery,
+ * instead of doing it here.
+ */
+ if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) &&
+ ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) ||
+ ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)))
+ {
+ /* Queue it */
+ KeInsertQueueDpc(TimerDpc,
+ UlongToPtr(SystemTime.LowPart),
+ UlongToPtr(SystemTime.HighPart));
+ }
+ else
+#endif
+ {
+ /* 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're done processing */
if (!(ActiveTimers) || !(Timers))
@@ -311,7 +333,10 @@
PKDPC TimerDpc;
ULONG Period;
DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS];
-
+#ifdef CONFIG_SMP
+ PKPRCB Prcb = KeGetCurrentPrcb();
+#endif
+
/* Query system */
KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
@@ -357,21 +382,40 @@
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
+#ifdef CONFIG_SMP
+ /*
+ * If the DPC is targeted to another processor,
+ * then insert it into that processor's DPC queue
+ * instead of delivering it now.
+ * If the DPC is a threaded DPC, and the current CPU
+ * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
+ * then also insert it into the DPC queue for threaded delivery,
+ * instead of doing it here.
+ */
+ if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) &&
+ ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) ||
+ ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)))
+ {
+ /* Queue it */
+ KeInsertQueueDpc(TimerDpc,
+ UlongToPtr(SystemTime.LowPart),
+ UlongToPtr(SystemTime.HighPart));
+ }
+ else
#endif
+ {
+ /* Setup the DPC Entry */
+ DpcEntry[DpcCalls].Dpc = TimerDpc;
+ DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
+ DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
+ DpcCalls++;
+ ASSERT(DpcCalls < MAX_TIMER_DPCS);
+ }
+ }
}
/* Check if we still have DPC entries */
Author: fireball
Date: Sat Nov 1 10:33:05 2008
New Revision: 37132
URL: http://svn.reactos.org/svn/reactos?rev=37132&view=rev
Log:
- 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.
Modified:
trunk/reactos/ntoskrnl/include/internal/ke.h
trunk/reactos/ntoskrnl/include/internal/ke_x.h
trunk/reactos/ntoskrnl/ke/clock.c
trunk/reactos/ntoskrnl/ke/dpc.c
trunk/reactos/ntoskrnl/ke/timerobj.c
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] Sat Nov 1 10:33:05 2008
@@ -286,6 +286,13 @@
IN ULONG Hand
);
+VOID
+FASTCALL
+KiTimerListExpire(
+ IN PLIST_ENTRY ExpiredListHead,
+ IN KIRQL OldIrql
+);
+
BOOLEAN
FASTCALL
KiInsertTreeTimer(
Modified: trunk/reactos/ntoskrnl/include/internal/ke_x.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ke_x.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/ke_x.h [iso-8859-1] Sat Nov 1 10:33:05 2008
@@ -1100,6 +1100,37 @@
}
//
+// 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.
//
@@ -1125,6 +1156,57 @@
/* Do nothing, just release the lock */
KiReleaseTimerLock(LockQueue);
}
+}
+
+//
+// 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;
}
//
Modified: trunk/reactos/ntoskrnl/ke/clock.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/clock.c?rev=37…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/clock.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/clock.c [iso-8859-1] Sat Nov 1 10:33:05 2008
@@ -40,7 +40,6 @@
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 @@
/* 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 @@
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 @@
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 @@
KiReleaseTimerLock(LockQueue);
}
- /* FIXME: Process expired timers! */
- KiReleaseDispatcherLock(OldIrql);
+ /* Process expired timers. This releases the dispatcher lock. */
+ KiTimerListExpire(&TempList2, OldIrql);
/* Revert affinity */
KeRevertToUserAffinityThread();
Modified: trunk/reactos/ntoskrnl/ke/dpc.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/dpc.c?rev=3713…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/dpc.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/dpc.c [iso-8859-1] Sat Nov 1 10:33:05 2008
@@ -86,7 +86,6 @@
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 @@
{
/* 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 @@
}
/* Check if we have a DPC */
+#ifndef CONFIG_SMP
if (TimerDpc)
{
/* Setup the DPC Entry */
@@ -199,7 +190,11 @@
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))
@@ -295,6 +290,108 @@
/* Lower IRQL if we need to */
if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql);
+ }
+ else
+ {
+ /* Unlock the dispatcher */
+ KiReleaseDispatcherLock(OldIrql);
+ }
+}
+
+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
{
Modified: trunk/reactos/ntoskrnl/ke/timerobj.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/timerobj.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/timerobj.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/timerobj.c [iso-8859-1] Sat Nov 1 10:33:05 2008
@@ -29,71 +29,29 @@
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)
- {
- /* Get System Time */
- KeQuerySystemTime(&SystemTime);
-
- /* Do the conversion */
- DifferenceTime.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
-
- /* Make sure it hasn't already expired */
- Timer->Header.Absolute = TRUE;
- if (DifferenceTime.HighPart >= 0)
+ /* Setup the timer's due time */
+ if (KiComputeDueTime(Timer, Interval, &Hand))
+ {
+ /* Acquire the lock */
+ LockQueue = KiAcquireTimerLock(Hand);
+
+ /* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* Set Default Timer Data */
Timer->Dpc = Dpc;
Timer->Period = Period;
-
- /* 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;
-
- /* 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);
-
+ if (!KiComputeDueTime(Timer, DueTime, &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);
+ }
+ else
+ {
+ /* Insert the timer */
+ Timer->Header.SignalState = FALSE;
+ KxInsertTimer(Timer, Hand);
+ }
+
/* Exit the dispatcher */
KiExitDispatcher(OldIrql);