<html>
<head>
<style>
<!--
body { background-color:#ffffff }
.file { border:1px solid #eeeeee; margin-top:1em; margin-bottom:1em }
.pathname { font-family:monospace; float:right }
.fileheader { margin-bottom:.5em }
.diff { margin:0 }
.tasklist { padding:4px; border:1px dashed #000000; margin-top:1em }
.tasklist ul { margin-top:0; margin-bottom:0 }
tr.alt { background-color:#eeeeee }
#added { background-color:#ddffdd }
#addedchars { background-color:#99ff99; font-weight:bolder }
tr.alt #added { background-color:#ccf7cc }
#removed { background-color:#ffdddd }
#removedchars { background-color:#ff9999; font-weight:bolder }
tr.alt #removed { background-color:#f7cccc }
#info { color:#888888 }
#context { background-color:#eeeeee }
td {padding-left:.3em; padding-right:.3em }
tr.head { border-bottom-width:1px; border-bottom-style:solid }
tr.head td { padding:0; padding-top:.2em }
.task { background-color:#ffff00 }
.comment { padding:4px; border:1px dashed #000000; background-color:#ffffdd }
.error { color:red }
hr { border-width:0px; height:2px; background:black }
-->
</style>
</head>
<body>
<pre class="comment">- Disable APC Queuing & Flush APC queues during thread shutdown.
- Detect if Kernel APCs were pending during thread shutdown.
- Call Lego Routine, if registered, during thread shutdown.</pre><pre class="diff" id="context">Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
Modified: trunk/reactos/ntoskrnl/ke/apc.c
Modified: trunk/reactos/ntoskrnl/ke/kthread.c
Modified: trunk/reactos/ntoskrnl/ps/kill.c
Modified: trunk/reactos/ntoskrnl/ps/notify.c
</pre><hr /><div class="file">
<div class="fileheader"><big><b>Modified: trunk/reactos/ntoskrnl/include/internal/ke.h</b></big></div>
<pre class="diff"><small id="info">--- trunk/reactos/ntoskrnl/include/internal/ke.h        2005-07-23 13:43:52 UTC (rev 16704)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h        2005-07-23 17:40:48 UTC (rev 16705)
@@ -253,6 +253,10 @@
</small></pre><pre class="diff" id="context"> STDCALL
KeForceResumeThread(IN PKTHREAD Thread);
</pre><pre class="diff" id="added">+BOOLEAN
+STDCALL
+KeDisableThreadApcQueueing(IN PKTHREAD Thread);
+
</pre><pre class="diff" id="context"> BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
VOID inline FASTCALL KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread);
@@ -292,6 +296,12 @@
</pre><pre class="diff" id="context">                          IN PVOID SystemArgument1,
                         IN PVOID SystemArgument2);
</pre><pre class="diff" id="added">+PLIST_ENTRY
+STDCALL
+KeFlushQueueApc(IN PKTHREAD Thread,
+ IN KPROCESSOR_MODE PreviousMode);
+
+
</pre><pre class="diff" id="context"> VOID STDCALL KiAttachProcess(struct _KTHREAD *Thread, struct _KPROCESS *Process, KIRQL ApcLock, struct _KAPC_STATE *SavedApcState);
VOID STDCALL KiSwapProcess(struct _KPROCESS *NewProcess, struct _KPROCESS *OldProcess);
</pre></div>
<hr /><div class="file">
<div class="fileheader"><big><b>Modified: trunk/reactos/ntoskrnl/include/internal/ps.h</b></big></div>
<pre class="diff"><small id="info">--- trunk/reactos/ntoskrnl/include/internal/ps.h        2005-07-23 13:43:52 UTC (rev 16704)
+++ trunk/reactos/ntoskrnl/include/internal/ps.h        2005-07-23 17:40:48 UTC (rev 16705)
@@ -184,6 +184,10 @@
</small></pre><pre class="diff" id="context"> STDCALL
PspRunCreateProcessNotifyRoutines(PEPROCESS, BOOLEAN);
</pre><pre class="diff" id="added">+VOID
+STDCALL
+PspRunLegoRoutine(IN PKTHREAD Thread);
+
</pre><pre class="diff" id="context"> VOID INIT_FUNCTION PsInitJobManagment(VOID);
/* CLIENT ID */
</pre></div>
<hr /><div class="file">
<div class="fileheader"><big><b>Modified: trunk/reactos/ntoskrnl/ke/apc.c</b></big></div>
<pre class="diff"><small id="info">--- trunk/reactos/ntoskrnl/ke/apc.c        2005-07-23 13:43:52 UTC (rev 16704)
+++ trunk/reactos/ntoskrnl/ke/apc.c        2005-07-23 17:40:48 UTC (rev 16705)
@@ -270,14 +270,14 @@
</small></pre><pre class="diff" id="context"> */
if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) {
</pre><pre class="diff" id="removed">- DPRINT<span id="removedchars"> </span>("Inserting the Process Exit APC into the Queue\n");
</pre><pre class="diff" id="added">+ DPRINT<span id="addedchars">1</span>("Inserting the Process Exit APC into the Queue\n");
</pre><pre class="diff" id="context"> Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
&Apc->ApcListEntry);
} else if (Apc->NormalRoutine == NULL) {
</pre><pre class="diff" id="removed">- DPRINT<span id="removedchars"> </span>("Inserting Special APC %x into the Queue\n", Apc);
</pre><pre class="diff" id="added">+ DPRINT("Inserting Special APC %x into the Queue\n", Apc);
</pre><pre class="diff" id="context">
for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink;
ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode];
@@ -293,7 +293,7 @@
</pre><pre class="diff" id="context">
} else {
</pre><pre class="diff" id="removed">- DPRINT<span id="removedchars"> </span>("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode);
</pre><pre class="diff" id="added">+ DPRINT("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode);
</pre><pre class="diff" id="context"> InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
&Apc->ApcListEntry);
}
@@ -441,6 +441,73 @@
</pre><pre class="diff" id="context"> }
/*++
</pre><pre class="diff" id="added">+ * KeFlushQueueApc
+ *
+ * The KeFlushQueueApc routine flushes all APCs of the given processor mode
+ * from the specified Thread's APC queue.
+ *
+ * Params:
+ * Thread - Pointer to the thread whose APC queue will be flushed.
+ *
+ * PreviousMode - Specifies which APC Queue to flush.
+ *
+ * Returns:
+ * A pointer to the first entry in the flushed APC queue.
+ *
+ * Remarks:
+ * If the routine returns NULL, it means that no APCs were to be flushed.
+ *
+ * Callers of KeFlushQueueApc must be running at DISPATCH_LEVEL or lower.
+ *
+ *--*/
+PLIST_ENTRY
+STDCALL
+KeFlushQueueApc(IN PKTHREAD Thread,
+ IN KPROCESSOR_MODE PreviousMode)
+{
+ KIRQL OldIrql;
+ PKAPC Apc;
+ PLIST_ENTRY ApcEntry, CurrentEntry;
+
+ /* Lock the Dispatcher Database and APC Queue */
+ OldIrql = KeAcquireDispatcherDatabaseLock();
+ KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
+
+ /* Check if the list is empty */
+ if (IsListEmpty(&Thread->ApcState.ApcListHead[PreviousMode]))
+ {
+ /* We'll return NULL */
+ ApcEntry = NULL;
+ }
+ else
+ {
+ /* Remove this one */
+ RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]);
+ CurrentEntry = ApcEntry;
+
+ /* Remove all the other ones too, if present */
+ do
+ {
+ /* Get the APC */
+ Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
+
+ /* Move to the next one */
+ CurrentEntry = CurrentEntry->Flink;
+
+ /* Mark it as not inserted */
+ Apc->Inserted = FALSE;
+ } while (ApcEntry != CurrentEntry);
+ }
+
+ /* Release the locks */
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+
+ /* Return the first entry */
+ return ApcEntry;
+}
+
+/*++
</pre><pre class="diff" id="context"> * KeRemoveQueueApc
*
* The KeRemoveQueueApc routine removes a given APC object from the system
</pre></div>
<hr /><div class="file">
<div class="fileheader"><big><b>Modified: trunk/reactos/ntoskrnl/ke/kthread.c</b></big></div>
<pre class="diff"><small id="info">--- trunk/reactos/ntoskrnl/ke/kthread.c        2005-07-23 13:43:52 UTC (rev 16704)
+++ trunk/reactos/ntoskrnl/ke/kthread.c        2005-07-23 17:40:48 UTC (rev 16705)
@@ -387,6 +387,29 @@
</small></pre><pre class="diff" id="context"> return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
}
</pre><pre class="diff" id="added">+BOOLEAN
+STDCALL
+KeDisableThreadApcQueueing(IN PKTHREAD Thread)
+{
+ KIRQL OldIrql;
+ BOOLEAN PreviousState;
+
+ /* Lock the Dispatcher Database */
+ OldIrql = KeAcquireDispatcherDatabaseLock();
+
+ /* Save old state */
+ PreviousState = Thread->ApcQueueable;
+
+ /* Disable it now */
+ Thread->ApcQueueable = FALSE;
+
+ /* Release the Lock */
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+
+ /* Return old state */
+ return PreviousState;
+}
+
</pre><pre class="diff" id="context"> VOID
STDCALL
KeRundownThread(VOID)
</pre></div>
<hr /><div class="file">
<div class="fileheader"><big><b>Modified: trunk/reactos/ntoskrnl/ps/kill.c</b></big></div>
<pre class="diff"><small id="info">--- trunk/reactos/ntoskrnl/ps/kill.c        2005-07-23 13:43:52 UTC (rev 16704)
+++ trunk/reactos/ntoskrnl/ps/kill.c        2005-07-23 17:40:48 UTC (rev 16705)
@@ -213,6 +213,8 @@
</small></pre><pre class="diff" id="context"> PTERMINATION_PORT TerminationPort;
PTEB Teb;
KIRQL oldIrql;
</pre><pre class="diff" id="added">+ PLIST_ENTRY ApcEntry, CurrentApc;
+ PKAPC Apc;
</pre><pre class="diff" id="context">
DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
@@ -332,6 +334,50 @@
</pre><pre class="diff" id="context"> /* Rundown Mutexes */
KeRundownThread();
</pre><pre class="diff" id="added">+ /* Disable new APC Queuing, this is as far as we'll let them go */
+ KeDisableThreadApcQueueing(&CurrentThread->Tcb);
+
+ /* Flush the User APCs */
+ if ((ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode)))
+ {
+ CurrentApc = ApcEntry;
+ do
+ {
+ /* Get the APC */
+ Apc = CONTAINING_RECORD(CurrentApc, KAPC, ApcListEntry);
+
+ /* Move to the next one */
+ CurrentApc = CurrentApc->Flink;
+
+ /* Rundown the APC or de-allocate it */
+ if (Apc->RundownRoutine)
+ {
+ /* Call its own routine */
+ (Apc->RundownRoutine)(Apc);
+ }
+ else
+ {
+ /* Do it ourselves */
+ ExFreePool(Apc);
+ }
+ }
+ while (CurrentApc != ApcEntry);
+ }
+
+ /* Call the Lego routine */
+ if (CurrentThread->Tcb.LegoData) PspRunLegoRoutine(&CurrentThread->Tcb);
+
+ /* Flush the APC queue, which should be empty */
+ if ((ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode)))
+ {
+ /* Bugcheck time */
+ KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
+ (ULONG_PTR)ApcEntry,
+ CurrentThread->Tcb.KernelApcDisable,
+ oldIrql,
+ 0);
+ }
+
</pre><pre class="diff" id="context"> /* Terminate the Thread from the Scheduler */
KeTerminateThread(0);
DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
</pre></div>
<hr /><div class="file">
<div class="fileheader"><big><b>Modified: trunk/reactos/ntoskrnl/ps/notify.c</b></big></div>
<pre class="diff"><small id="info">--- trunk/reactos/ntoskrnl/ps/notify.c        2005-07-23 13:43:52 UTC (rev 16704)
+++ trunk/reactos/ntoskrnl/ps/notify.c        2005-07-23 17:40:48 UTC (rev 16705)
@@ -26,9 +26,10 @@
</small></pre><pre class="diff" id="context">
static PLOAD_IMAGE_NOTIFY_ROUTINE
PspLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT];
</pre><pre class="diff" id="added">+
+typedef VOID (STDCALL *PLEGO_NOTIFY_ROUTINE)(IN PKTHREAD Thread);
+static PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine;
</pre><pre class="diff" id="context">
</pre><pre class="diff" id="removed">-static PVOID PspLegoNotifyRoutine;
-
</pre><pre class="diff" id="context"> /* FUNCTIONS ***************************************************************/
/*
@@ -231,4 +232,12 @@
</pre><pre class="diff" id="context"> }
}
</pre><pre class="diff" id="added">+VOID
+STDCALL
+PspRunLegoRoutine(IN PKTHREAD Thread)
+{
+ /* Call it */
+ if (PspLegoNotifyRoutine) (PspLegoNotifyRoutine)(Thread);
+}
+
</pre><pre class="diff" id="context"> /* EOF */
</pre>
</div>
</body>
</html>