<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 &amp; 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,
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;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"> &nbsp; &nbsp; */
 &nbsp; &nbsp; if ((Apc-&gt;ApcMode != KernelMode) &amp;&amp; (Apc-&gt;KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) {
 
</pre><pre class="diff" id="removed">- &nbsp; &nbsp; &nbsp; &nbsp;DPRINT<span id="removedchars"> </span>(&quot;Inserting the Process Exit APC into the Queue\n&quot;);
</pre><pre class="diff" id="added">+ &nbsp; &nbsp; &nbsp; &nbsp;DPRINT<span id="addedchars">1</span>(&quot;Inserting the Process Exit APC into the Queue\n&quot;);
</pre><pre class="diff" id="context"> &nbsp; &nbsp; &nbsp; &nbsp; Thread-&gt;ApcStatePointer[(int)Apc-&gt;ApcStateIndex]-&gt;UserApcPending = TRUE;
 &nbsp; &nbsp; &nbsp; &nbsp; InsertHeadList(&amp;Thread-&gt;ApcStatePointer[(int)Apc-&gt;ApcStateIndex]-&gt;ApcListHead[(int)Apc-&gt;ApcMode],
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;Apc-&gt;ApcListEntry);
 
 &nbsp; &nbsp; } else if (Apc-&gt;NormalRoutine == NULL) {
 
</pre><pre class="diff" id="removed">- &nbsp; &nbsp; &nbsp; &nbsp;DPRINT<span id="removedchars"> </span>(&quot;Inserting Special APC %x into the Queue\n&quot;, Apc);
</pre><pre class="diff" id="added">+ &nbsp; &nbsp; &nbsp; &nbsp;DPRINT(&quot;Inserting Special APC %x into the Queue\n&quot;, Apc);
</pre><pre class="diff" id="context"> 
 &nbsp; &nbsp; &nbsp; &nbsp; for (ApcListEntry = Thread-&gt;ApcStatePointer[(int)Apc-&gt;ApcStateIndex]-&gt;ApcListHead[(int)Apc-&gt;ApcMode].Flink;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ApcListEntry != &amp;Thread-&gt;ApcStatePointer[(int)Apc-&gt;ApcStateIndex]-&gt;ApcListHead[(int)Apc-&gt;ApcMode];
@@ -293,7 +293,7 @@
</pre><pre class="diff" id="context"> 
 &nbsp; &nbsp; } else {
 
</pre><pre class="diff" id="removed">- &nbsp; &nbsp; &nbsp; &nbsp;DPRINT<span id="removedchars"> </span>(&quot;Inserting Normal APC %x into the %x Queue\n&quot;, Apc, Apc-&gt;ApcMode);
</pre><pre class="diff" id="added">+ &nbsp; &nbsp; &nbsp; &nbsp;DPRINT(&quot;Inserting Normal APC %x into the %x Queue\n&quot;, Apc, Apc-&gt;ApcMode);
</pre><pre class="diff" id="context"> &nbsp; &nbsp; &nbsp; &nbsp; InsertTailList(&amp;Thread-&gt;ApcStatePointer[(int)Apc-&gt;ApcStateIndex]-&gt;ApcListHead[(int)Apc-&gt;ApcMode],
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;Apc-&gt;ApcListEntry);
 &nbsp; &nbsp; }
@@ -441,6 +441,73 @@
</pre><pre class="diff" id="context"> }
 
 /*++
</pre><pre class="diff" id="added">+ * KeFlushQueueApc
+ *
+ * &nbsp; &nbsp; The KeFlushQueueApc routine flushes all APCs of the given processor mode
+ * &nbsp; &nbsp; from the specified Thread's APC queue.
+ *
+ * Params:
+ * &nbsp; &nbsp; Thread - Pointer to the thread whose APC queue will be flushed.
+ *
+ * &nbsp; &nbsp; PreviousMode - Specifies which APC Queue to flush.
+ *
+ * Returns:
+ * &nbsp; &nbsp; A pointer to the first entry in the flushed APC queue.
+ *
+ * Remarks:
+ * &nbsp; &nbsp; If the routine returns NULL, it means that no APCs were to be flushed.
+ *
+ * &nbsp; &nbsp; Callers of KeFlushQueueApc must be running at DISPATCH_LEVEL or lower.
+ *
+ *--*/
+PLIST_ENTRY
+STDCALL
+KeFlushQueueApc(IN PKTHREAD Thread,
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IN KPROCESSOR_MODE PreviousMode)
+{
+ &nbsp; &nbsp;KIRQL OldIrql;
+ &nbsp; &nbsp;PKAPC Apc;
+ &nbsp; &nbsp;PLIST_ENTRY ApcEntry, CurrentEntry;
+
+ &nbsp; &nbsp;/* Lock the Dispatcher Database and APC Queue */
+ &nbsp; &nbsp;OldIrql = KeAcquireDispatcherDatabaseLock();
+ &nbsp; &nbsp;KeAcquireSpinLock(&amp;Thread-&gt;ApcQueueLock, &amp;OldIrql);
+
+ &nbsp; &nbsp;/* Check if the list is empty */
+ &nbsp; &nbsp;if (IsListEmpty(&amp;Thread-&gt;ApcState.ApcListHead[PreviousMode]))
+ &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp;/* We'll return NULL */
+ &nbsp; &nbsp; &nbsp; &nbsp;ApcEntry = NULL;
+ &nbsp; &nbsp;}
+ &nbsp; &nbsp;else
+ &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp;/* Remove this one */
+ &nbsp; &nbsp; &nbsp; &nbsp;RemoveEntryList(&amp;Thread-&gt;ApcState.ApcListHead[PreviousMode]);
+ &nbsp; &nbsp; &nbsp; &nbsp;CurrentEntry = ApcEntry;
+
+ &nbsp; &nbsp; &nbsp; &nbsp;/* Remove all the other ones too, if present */
+ &nbsp; &nbsp; &nbsp; &nbsp;do
+ &nbsp; &nbsp; &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Get the APC */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Move to the next one */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CurrentEntry = CurrentEntry-&gt;Flink;
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Mark it as not inserted */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Apc-&gt;Inserted = FALSE;
+ &nbsp; &nbsp; &nbsp; &nbsp;} while (ApcEntry != CurrentEntry);
+ &nbsp; &nbsp;}
+
+ &nbsp; &nbsp;/* Release the locks */
+ &nbsp; &nbsp;KeReleaseSpinLock(&amp;Thread-&gt;ApcQueueLock, OldIrql);
+ &nbsp; &nbsp;KeReleaseDispatcherDatabaseLock(OldIrql);
+
+ &nbsp; &nbsp;/* Return the first entry */
+ &nbsp; &nbsp;return ApcEntry;
+}
+
+/*++
</pre><pre class="diff" id="context"> &nbsp;* KeRemoveQueueApc
 &nbsp;*
 &nbsp;* &nbsp; &nbsp; 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"> &nbsp; &nbsp; return (ULONG)PsGetCurrentThread()-&gt;Tcb.PreviousMode;
 }
 
</pre><pre class="diff" id="added">+BOOLEAN
+STDCALL
+KeDisableThreadApcQueueing(IN PKTHREAD Thread)
+{
+ &nbsp; &nbsp;KIRQL OldIrql;
+ &nbsp; &nbsp;BOOLEAN PreviousState;
+
+ &nbsp; &nbsp;/* Lock the Dispatcher Database */
+ &nbsp; &nbsp;OldIrql = KeAcquireDispatcherDatabaseLock();
+
+ &nbsp; &nbsp;/* Save old state */
+ &nbsp; &nbsp;PreviousState = Thread-&gt;ApcQueueable;
+
+ &nbsp; &nbsp;/* Disable it now */
+ &nbsp; &nbsp;Thread-&gt;ApcQueueable = FALSE;
+
+ &nbsp; &nbsp;/* Release the Lock */
+ &nbsp; &nbsp;KeReleaseDispatcherDatabaseLock(OldIrql);
+
+ &nbsp; &nbsp;/* Return old state */
+ &nbsp; &nbsp;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"> &nbsp; &nbsp; PTERMINATION_PORT TerminationPort;
 &nbsp; &nbsp; PTEB Teb;
 &nbsp; &nbsp; KIRQL oldIrql;
</pre><pre class="diff" id="added">+ &nbsp; &nbsp;PLIST_ENTRY ApcEntry, CurrentApc;
+ &nbsp; &nbsp;PKAPC Apc;
</pre><pre class="diff" id="context"> 
 &nbsp; &nbsp; DPRINT(&quot;PspExitThread(ExitStatus %x), Current: 0x%x\n&quot;, ExitStatus, PsGetCurrentThread());
 
@@ -332,6 +334,50 @@
</pre><pre class="diff" id="context"> &nbsp; &nbsp; /* Rundown Mutexes */
 &nbsp; &nbsp; KeRundownThread();
 
</pre><pre class="diff" id="added">+ &nbsp; &nbsp;/* Disable new APC Queuing, this is as far as we'll let them go */
+ &nbsp; &nbsp;KeDisableThreadApcQueueing(&amp;CurrentThread-&gt;Tcb);
+
+ &nbsp; &nbsp;/* Flush the User APCs */
+ &nbsp; &nbsp;if ((ApcEntry = KeFlushQueueApc(&amp;CurrentThread-&gt;Tcb, UserMode)))
+ &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp;CurrentApc = ApcEntry;
+ &nbsp; &nbsp; &nbsp; &nbsp;do
+ &nbsp; &nbsp; &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Get the APC */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Apc = CONTAINING_RECORD(CurrentApc, KAPC, ApcListEntry);
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Move to the next one */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CurrentApc = CurrentApc-&gt;Flink;
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Rundown the APC or de-allocate it */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (Apc-&gt;RundownRoutine)
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Call its own routine */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(Apc-&gt;RundownRoutine)(Apc);
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Do it ourselves */
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ExFreePool(Apc);
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}
+ &nbsp; &nbsp; &nbsp; &nbsp;}
+ &nbsp; &nbsp; &nbsp; &nbsp;while (CurrentApc != ApcEntry);
+ &nbsp; &nbsp;}
+
+ &nbsp; &nbsp;/* Call the Lego routine */
+ &nbsp; &nbsp;if (CurrentThread-&gt;Tcb.LegoData) PspRunLegoRoutine(&amp;CurrentThread-&gt;Tcb);
+
+ &nbsp; &nbsp;/* Flush the APC queue, which should be empty */
+ &nbsp; &nbsp;if ((ApcEntry = KeFlushQueueApc(&amp;CurrentThread-&gt;Tcb, KernelMode)))
+ &nbsp; &nbsp;{
+ &nbsp; &nbsp; &nbsp; &nbsp;/* Bugcheck time */
+ &nbsp; &nbsp; &nbsp; &nbsp;KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (ULONG_PTR)ApcEntry,
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CurrentThread-&gt;Tcb.KernelApcDisable,
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oldIrql,
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0);
+ &nbsp; &nbsp;}
+
</pre><pre class="diff" id="context"> &nbsp; &nbsp; /* Terminate the Thread from the Scheduler */
 &nbsp; &nbsp; KeTerminateThread(0);
 &nbsp; &nbsp; DPRINT1(&quot;Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n&quot;, 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"> &nbsp; &nbsp; }
 }
 
</pre><pre class="diff" id="added">+VOID
+STDCALL
+PspRunLegoRoutine(IN PKTHREAD Thread)
+{
+ &nbsp; &nbsp;/* Call it */
+ &nbsp; &nbsp;if (PspLegoNotifyRoutine) (PspLegoNotifyRoutine)(Thread);
+}
+
</pre><pre class="diff" id="context"> /* EOF */
</pre>
</div>

</body>
</html>