Thread/Process Termination/Repeaing Rewrite + Fixes
---------------------------------------------------

    - ps/cid.c: 
            * Moved CID Lookup functions here
            
    - ps/security.c: 
            * Moved all security related functions here. Makes other files neater and security functions
              easier to locate.
              
    - ps/thread.c: 
            * Moved most of the Thread Scheduling/Dispatching code that belongs in the Kernel to /ke and
              renamed functions from Ps to Ki.
            * Implemented PsIsSystemThread.
            * Removed Reaper Thread Init (now obsolete).
            * Renamed PiDeleteThread to PspDeleteThread.
            * Moved Thread State functions from tinfo.c to here.
            
    - ps/process.c:
            * Removed Query/Set Process functions and moved to ps/query.c
            * Renamed PiDeletePRocess to PspDeleteProcess
            * Removed obsoleted Process Termination functions, moved persistent one to kill.c
    
    - ps/create.c:
            * Moved the security APIs to security.c
            * Correctly implemented PsCreateSystemThread to actually create system threads.
        
            
    - ps/suspend.c
            * Rewrote Nt Executive functions to use Kernel functions.
            * Moved Ps* Routines into ke/kthread.c and fixed them. The implementation was wrong in
              some aspects, especially the issue of the APC looping around the KeWaitXxx call and the
              fact that the routines excluded/ignored the FreezeCount.
            
    - ps/debug.c
            * Fixed completely broken implementation of Get/SetThreadContext. The old version crashed
              when called and did not work at all. Suspend Regression test now works.
            * Moved Context<->TrapFrame functions to ke/i386/
            * Combined Set/GetThreadContext APCs into a single one, and used special context structure.
            
    - ps/query.c:
            * Moved Thread/Process Query/Set Routines here.
            
    - ps/tinfo.c:
            * Removed.
            
    - ps/kill.c
            * Removed complicated Process Termination semantics and useless Attach/Detach in favor for
              a much more lightweight function which performs the same tasks as before and actually works.
              TaskManager can now terminate foreign processes.
            * Rewrote Thread Reaping to use the HyperCritical Work Queue instead of manually controlled
              thread. This results in much less code as well as an increase in speed and less micro
              management. The reaper is PspReapRoutine. Closing CMD.EXE now works properly without
              requiring masks that were added as hacks to allow it.
            * Renamed PiTerminateProcessThreads to PspTerminateProcessThreads. Fixed it to work with new
              termination code.
            * Added PspDeleteProcess to handle Process Object deletion. Kills the CID Handle here as done
              by Hartmut.
            * Added PspDeletethread here.
            * Renamed and rewrote PsTerminateCurrentThread to PspExitThread. Used NT Implementation out-
              lined in Windows Internals, Chapter 13. Uses less locks, a more concise order of actions,
              actually parses the Termination Ports, handles Dbgk notification. Timers are now rundown,
              and Mutex rundown is in a dedicated Kernel function. Final termination handled by KeTerminate
              Thread as documented.
            * Renamed PsTerminateOtherThread to PspTerminateThreadByPointer and modified implementation to
              be compatible with the changes above.
            * Renamed and regrouped Process Termination into PspExitProcess. Also implemented as described
              above, and moved each subsystem specific termination helper into its own subsytem.
            * Improved NtTerminateProcess and added more debugging messages.
            * Improved NtTerminateThread and added check against System Thread and made it compatible with
              new implementation.
            * Corrected PsTerminateSystemThread now that we support System Threads.
            * Corrected NtRegisterThreadTerminatePort to use same structure name as on windows for the 
              port, and added tag to pool allocation (documented in pooltag.txt)
    
    include/internal/*.h:
    
            * Defined Scheduler Functions and misc new functions or renamed functions.
            
    ke/apc.c:
    
            * Fixed critical bug where APCs were not delivered at all if the thread wastion and cancels any timers that are associated
              to a thread, as well as their APCs and DPCs.
      
    REGRESSIONS FOUND: NONE
    
    BUGS/REGRESSIOSN FIXED:
                * Thread/Get Set Context now works.
                * Suspend Regression test now works.
                * Task manager can now kill foreign processes, even hung ones (like it should).
                * ExitProcess/closing cmd.exe with the 'x' button now works correctly without hacks.
      KNOWN ISSUES: I left a bit of a mess in the headers and some stuff still needs to be moved into the right 
                  places. I just wanted to have this first part ready first, so that it won't get too big.
Modified: trunk/reactos/ntoskrnl/Makefile
Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
Modified: trunk/reactos/ntoskrnl/ex/timer.c
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
Modified: trunk/reactos/ntoskrnl/include/internal/ob.h
Modified: trunk/reactos/ntoskrnl/include/internal/port.h
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
Modified: trunk/reactos/ntoskrnl/ke/apc.c
Modified: trunk/reactos/ntoskrnl/ke/dpc.c
Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c
Modified: trunk/reactos/ntoskrnl/ke/i386/tskswitch.S
Modified: trunk/reactos/ntoskrnl/ke/kthread.c
Modified: trunk/reactos/ntoskrnl/ke/main.c
Modified: trunk/reactos/ntoskrnl/ke/process.c
Modified: trunk/reactos/ntoskrnl/ke/queue.c
Modified: trunk/reactos/ntoskrnl/ke/wait.c
Modified: trunk/reactos/ntoskrnl/ob/handle.c
Modified: trunk/reactos/ntoskrnl/ps/cid.c
Modified: trunk/reactos/ntoskrnl/ps/create.c
Modified: trunk/reactos/ntoskrnl/ps/debug.c
Modified: trunk/reactos/ntoskrnl/ps/idle.c
Modified: trunk/reactos/ntoskrnl/ps/kill.c
Modified: trunk/reactos/ntoskrnl/ps/process.c
Modified: trunk/reactos/ntoskrnl/ps/psmgr.c
Added: trunk/reactos/ntoskrnl/ps/query.c
Added: trunk/reactos/ntoskrnl/ps/security.c
Modified: trunk/reactos/ntoskrnl/ps/suspend.c
Modified: trunk/reactos/ntoskrnl/ps/thread.c
Deleted: trunk/reactos/ntoskrnl/ps/tinfo.c

Modified: trunk/reactos/ntoskrnl/Makefile
--- trunk/reactos/ntoskrnl/Makefile	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/Makefile	2005-03-18 05:53:04 UTC (rev 14174)
@@ -226,9 +226,10 @@
 	ps/locale.o \
 	ps/process.o \
 	ps/psmgr.o \
+	ps/query.o \
+	ps/security.o \
 	ps/suspend.o \
 	ps/thread.o \
-	ps/tinfo.o \
 	ps/win32.o \
 	ps/w32call.o
 

Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
--- trunk/reactos/ntoskrnl/cm/ntfunc.c	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/cm/ntfunc.c	2005-03-18 05:53:04 UTC (rev 14174)
@@ -2003,7 +2003,35 @@
 	return(STATUS_NOT_IMPLEMENTED);
 }
 
+#if 0
+NTSTATUS STDCALL
+NtNotifyChangeKey (IN HANDLE KeyHandle,
+		   IN HANDLE Event,
+		   IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+		   IN PVOID ApcContext OPTIONAL,
+		   OUT PIO_STATUS_BLOCK IoStatusBlock,
+		   IN ULONG CompletionFilter,
+		   IN BOOLEAN WatchSubtree,
+		   OUT PVOID Buffer,
+		   IN ULONG Length,
+		   IN BOOLEAN Asynchronous)
+{
+     return NtNotifyChangeMultipleKeys(KeyHandle,          
+                                       0,
+                                       NULL,
+                                       Event,
+                                       ApcRoutine,
+                                       ApcContext,
+                                       IoStatusBlock,
+                                       CompletionFilter,
+                                       WatchTree,
+                                       Buffer,
+                                       Length,
+                                       Asynchronous);
+}
 
+#endif
+
 NTSTATUS STDCALL
 NtQueryMultipleValueKey (IN HANDLE KeyHandle,
 			 IN OUT PKEY_VALUE_ENTRY ValueList,

Modified: trunk/reactos/ntoskrnl/ex/timer.c
--- trunk/reactos/ntoskrnl/ex/timer.c	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/ex/timer.c	2005-03-18 05:53:04 UTC (rev 14174)
@@ -55,6 +55,66 @@
 
 VOID
 STDCALL
+ExTimerRundown(VOID)
+{
+    PETHREAD Thread = PsGetCurrentThread();
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    BOOLEAN KillTimer = FALSE;
+    PETIMER Timer;
+    
+    /* Lock the Thread's Active Timer List*/
+    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
+    
+    /* Loop through all the timers */
+    CurrentEntry = Thread->ActiveTimerListHead.Flink;
+    while (CurrentEntry != &Thread->ActiveTimerListHead) {
+    
+        /* Get the Timer */
+        Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);
+        DPRINT("Timer, ThreadList: %x, %x\n", Timer, Thread);
+        
+        /* Unlock the list */
+        KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
+            
+        /* Lock the Timer */
+        KeAcquireSpinLock(&Timer->Lock, &OldIrql);
+        
+        /* Relock the active list */
+        KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);
+        
+        /* Make sure it's associated to us */
+        if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread)) {
+        
+            /* Remove it */
+            DPRINT("Removing from Thread: %x\n", Thread);
+            RemoveEntryList(&Thread->ActiveTimerListHead); 
+            KeCancelTimer(&Timer->KeTimer);
+            KeRemoveQueueDpc(&Timer->TimerDpc);
+            KeRemoveQueueApc(&Timer->TimerApc);   
+            Timer->ApcAssociated = FALSE;      
+            KillTimer = TRUE;
+        }
+                       
+        /* Unlock the list */
+        KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
+        
+        /* Unlock the Timer */
+        KeReleaseSpinLock(&Timer->Lock, OldIrql);
+        
+        /* Dereference it, if needed */
+        if (KillTimer) ObDereferenceObject(Timer);
+        
+        /* Loop again */
+        KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
+        CurrentEntry = CurrentEntry->Flink;
+    }       
+    
+    KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
+}
+
+VOID
+STDCALL
 ExpDeleteTimer(PVOID ObjectBody)
 {
     KIRQL OldIrql;

Modified: trunk/reactos/ntoskrnl/include/internal/ex.h
--- trunk/reactos/ntoskrnl/include/internal/ex.h	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/include/internal/ex.h	2005-03-18 05:53:04 UTC (rev 14174)
@@ -185,6 +185,10 @@
 NTSTATUS
 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId);
 
+VOID
+STDCALL
+ExTimerRundown(VOID);
+
 #define InterlockedDecrementUL(Addend) \
    (ULONG)InterlockedDecrement((PLONG)(Addend))
 

Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
--- trunk/reactos/ntoskrnl/include/internal/ke.h	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h	2005-03-18 05:53:04 UTC (rev 14174)
@@ -49,6 +49,35 @@
 #define IPI_REQUEST_DPC		    2
 #define IPI_REQUEST_FREEZE	    3
 
+/* threadsch.c ********************************************************************/
+
+/* Thread Scheduler Functions */
+
+/* Readies a Thread for Execution. */
+VOID 
+STDCALL
+KiDispatchThreadNoLock(ULONG NewThreadStatus);
+
+/* Readies a Thread for Execution. */
+VOID 
+STDCALL
+KiDispatchThread(ULONG NewThreadStatus);
+
+/* Puts a Thread into a block state. */
+VOID
+STDCALL
+KiBlockThread(PNTSTATUS Status, 
+              UCHAR Alertable, 
+              ULONG WaitMode,
+              UCHAR WaitReason);
+    
+/* Removes a thread out of a block state. */        
+VOID
+STDCALL
+KiUnblockThread(PKTHREAD Thread, 
+                PNTSTATUS WaitStatus, 
+                KPRIORITY Increment);
+
 /* ipi.c ********************************************************************/
 
 BOOLEAN STDCALL 
@@ -150,6 +179,29 @@
 VOID inline FASTCALL KeReleaseDispatcherDatabaseLock(KIRQL Irql);
 VOID inline FASTCALL KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID);
 
+VOID 
+STDCALL
+KeInitializeThread(struct _KPROCESS* Process, PKTHREAD Thread, BOOLEAN First);
+
+VOID
+STDCALL
+KeRundownThread(VOID);
+
+NTSTATUS KeReleaseThread(PKTHREAD Thread);
+
+VOID
+STDCALL
+KeStackAttachProcess (
+    IN struct _KPROCESS* Process,
+    OUT PKAPC_STATE ApcState
+    );
+
+VOID
+STDCALL
+KeUnstackDetachProcess (
+    IN PKAPC_STATE ApcState
+    );
+
 BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment);
 VOID STDCALL KeExpireTimers(PKDPC Apc,
 			    PVOID Arg1,
@@ -165,6 +217,10 @@
 KiAbortWaitThread(PKTHREAD Thread, 
                   NTSTATUS WaitStatus,
                   KPRIORITY Increment);
+                  
+ULONG
+STDCALL
+KeForceResumeThread(IN PKTHREAD Thread);
  
 BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
 
@@ -182,6 +238,18 @@
                   PVOID Reserved,
                   PKTRAP_FRAME TrapFrame);
 
+LONG 
+STDCALL 
+KiInsertQueue(IN PKQUEUE Queue, 
+              IN PLIST_ENTRY Entry, 
+              BOOLEAN Head);
+   
+ULONG
+STDCALL
+KeSetProcess(struct _KPROCESS* Process, 
+             KPRIORITY Increment);
+             
+                            
 VOID STDCALL KeInitializeEventPair(PKEVENT_PAIR EventPair);
 
 VOID STDCALL KiInitializeUserApc(IN PVOID Reserved,

Modified: trunk/reactos/ntoskrnl/include/internal/ob.h
--- trunk/reactos/ntoskrnl/include/internal/ob.h	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/include/internal/ob.h	2005-03-18 05:53:04 UTC (rev 14174)
@@ -302,7 +302,9 @@
 VOID FASTCALL
 ObpSetPermanentObject (IN PVOID ObjectBody, IN BOOLEAN Permanent);
 
-
+VOID
+STDCALL
+ObKillProcess(PEPROCESS Process);
 /* Security descriptor cache functions */
 
 NTSTATUS

Modified: trunk/reactos/ntoskrnl/include/internal/port.h
--- trunk/reactos/ntoskrnl/include/internal/port.h	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/include/internal/port.h	2005-03-18 05:53:04 UTC (rev 14174)
@@ -29,14 +29,6 @@
   ULONG		MaxPoolUsage; /* size of NP zone */
 } EPORT, * PEPORT;
 
-
-typedef struct _EPORT_TERMINATION_REQUEST
-{
-	LIST_ENTRY	ThreadListEntry;
-	PEPORT		Port;	
-} EPORT_TERMINATION_REQUEST, *PEPORT_TERMINATION_REQUEST;
-
-
 typedef struct _EPORT_CONNECT_REQUEST_MESSAGE
 {
   LPC_MESSAGE MessageHeader;
@@ -59,6 +51,11 @@
   UCHAR ConnectData[0];
 } EPORT_CONNECT_REPLY_MESSAGE, *PEPORT_CONNECT_REPLY_MESSAGE;
 
+typedef struct _TERMINATION_PORT {
+    LIST_ENTRY Links;
+    PVOID Port;
+} TERMINATION_PORT, *PTERMINATION_PORT;
+
 NTSTATUS STDCALL
 LpcRequestPort (PEPORT		Port,
 		PLPC_MESSAGE	LpcMessage);

Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
--- trunk/reactos/ntoskrnl/include/internal/ps.h	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/include/internal/ps.h	2005-03-18 05:53:04 UTC (rev 14174)
@@ -201,6 +201,7 @@
   UCHAR ActiveImpersonationInfo;
   ULONG PerformanceCountHigh;
   LIST_ENTRY ThreadListEntry;
+  BOOLEAN SystemThread;
 } ETHREAD;
 
 #include <poppack.h>
@@ -437,7 +438,6 @@
 VOID PsInitThreadManagment(VOID);
 VOID PsInitProcessManagment(VOID);
 VOID PsInitIdleThread(VOID);
-VOID PsDispatchThreadNoLock(ULONG NewThreadStatus);
 VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus);
 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
 VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus);
@@ -458,17 +458,23 @@
 		   KPROCESSOR_MODE AccessMode,
 		   BOOLEAN First);
 
-PACCESS_TOKEN PsReferenceEffectiveToken(PETHREAD Thread,
+PACCESS_TOKEN STDCALL PsReferenceEffectiveToken(PETHREAD Thread,
 					PTOKEN_TYPE TokenType,
 					PUCHAR b,
 					PSECURITY_IMPERSONATION_LEVEL Level);
 
-NTSTATUS PsOpenTokenOfProcess(HANDLE ProcessHandle,
+NTSTATUS STDCALL PsOpenTokenOfProcess(HANDLE ProcessHandle,
 			      PACCESS_TOKEN* Token);
-
+VOID
+STDCALL
+PspTerminateProcessThreads(PEPROCESS Process,
+                           NTSTATUS ExitStatus);
 NTSTATUS PsSuspendThread(PETHREAD Thread, PULONG PreviousCount);
 NTSTATUS PsResumeThread(PETHREAD Thread, PULONG PreviousCount);
-
+NTSTATUS
+STDCALL
+PspAssignPrimaryToken(PEPROCESS Process,
+                      HANDLE TokenHandle);
 VOID STDCALL PsExitSpecialApc(PKAPC Apc, 
 		      PKNORMAL_ROUTINE *NormalRoutine,
 		      PVOID *NormalContext,
@@ -497,27 +503,25 @@
 #define PROCESS_PRIO_RT				18
 
 
-VOID STDCALL
-KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First);
-NTSTATUS KeReleaseThread(PKTHREAD Thread);
+VOID STDCALL PiDeleteProcess(PVOID ObjectBody);
 
+VOID 
+STDCALL 
+PspReapRoutine(PVOID Context);
+
 VOID
 STDCALL
-KeStackAttachProcess (
-    IN PKPROCESS Process,
-    OUT PKAPC_STATE ApcState
-    );
+PspExitThread(NTSTATUS ExitStatus);
 
+extern LIST_ENTRY PspReaperListHead;
+extern WORK_QUEUE_ITEM PspReaperWorkItem;
+extern BOOLEAN PspReaping;
+
 VOID
 STDCALL
-KeUnstackDetachProcess (
-    IN PKAPC_STATE ApcState
-    );
+PspTerminateThreadByPointer(PETHREAD Thread,
+                            NTSTATUS ExitStatus);
 
-VOID STDCALL PiDeleteProcess(PVOID ObjectBody);
-VOID PsReapThreads(VOID);
-VOID PsInitializeThreadReaper(VOID);
-VOID PsQueueThreadReap(PETHREAD Thread);
 VOID PsUnfreezeOtherThread(PETHREAD Thread);
 VOID PsFreezeOtherThread(PETHREAD Thread);
 VOID PsFreezeProcessThreads(PEPROCESS Process);
@@ -525,19 +529,9 @@
 ULONG PsEnumThreadsByProcess(PEPROCESS Process);
 PEPROCESS PsGetNextProcess(PEPROCESS OldProcess);
 VOID
-STDCALL
-PsBlockThread(PNTSTATUS Status, 
-              UCHAR Alertable, 
-              ULONG WaitMode,
-              UCHAR WaitReason);
-VOID
-PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment);
-VOID
 PsApplicationProcessorInit(VOID);
 VOID
 PsPrepareForApplicationProcessorInit(ULONG Id);
-VOID
-PsInitReaperThread(VOID);
 VOID STDCALL
 PsIdleThreadMain(PVOID Context);
 
@@ -553,11 +547,20 @@
 PiSuspendThreadNormalRoutine(PVOID NormalContext,
 			     PVOID SystemArgument1,
 			     PVOID SystemArgument2);
-VOID STDCALL
-PsDispatchThread(ULONG NewThreadStatus);
 VOID
 PsInitialiseSuspendImplementation(VOID);
+NTSTATUS 
+STDCALL
+PspExitProcess(PEPROCESS Process);
 
+VOID 
+STDCALL 
+PspDeleteProcess(PVOID ObjectBody);
+
+VOID 
+STDCALL
+PspDeleteThread(PVOID ObjectBody);
+
 extern LONG PiNrThreadsAwaitingReaping;
 
 NTSTATUS

Modified: trunk/reactos/ntoskrnl/ke/apc.c
--- trunk/reactos/ntoskrnl/ke/apc.c	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/ke/apc.c	2005-03-18 05:53:04 UTC (rev 14174)
@@ -14,10 +14,6 @@
 #define NDEBUG
 #include <internal/debug.h>
 
-/* GLOBALS *******************************************************************/
-
-VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
-
 /* FUNCTIONS *****************************************************************/
 
 /*++
@@ -145,19 +141,15 @@
 }
 
 /*++
- * KeInsertQueueApc 
- * @implemented NT4
+ * KiInsertQueueApc 
  *
- *     The KeInsertQueueApc routine queues a APC for execution when the right
+ *     The KiInsertQueueApc routine queues a APC for execution when the right
  *     scheduler environment exists.
  *
  * Params:
  *     Apc - Pointer to an initialized control object of type DPC for which the
  *           caller provides the storage. 
  *
- *     SystemArgument[1,2] - Pointer to a set of two parameters that contain
- *                           untyped data.
- *
  *     PriorityBoost - Priority Boost to apply to the Thread.
  *
  * Returns:
@@ -173,45 +165,16 @@
  *--*/
 BOOLEAN
 STDCALL
-KeInsertQueueApc(PKAPC Apc,
-                 PVOID SystemArgument1,
-                 PVOID SystemArgument2,
+KiInsertQueueApc(PKAPC Apc,
                  KPRIORITY PriorityBoost)
-
 {
-    KIRQL OldIrql;
-    PKTHREAD Thread;
+    PKTHREAD Thread = Apc->Thread;
     PLIST_ENTRY ApcListEntry;
     PKAPC QueuedApc;
-   
-    ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
-    DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
-           "SystemArgument2 %x)\n",Apc,SystemArgument1,
-            SystemArgument2);
-
-    /* Lock the Dispatcher Database */
-    OldIrql = KeAcquireDispatcherDatabaseLock();
     
-    /* Get the Thread specified in the APC */
-    Thread = Apc->Thread;
-       
-    /* Make sure the thread allows APC Queues.
-    * The thread is not apc queueable, for instance, when it's (about to be) terminated.
-    */
-    if (Thread->ApcQueueable == FALSE) {
-        DPRINT("Thread doesn't allow APC Queues\n");
-        KeReleaseDispatcherDatabaseLock(OldIrql);
-        return FALSE;
-    }
-    
-    /* Set the System Arguments */
-    Apc->SystemArgument1 = SystemArgument1;
-    Apc->SystemArgument2 = SystemArgument2;
-
     /* Don't do anything if the APC is already inserted */
     if (Apc->Inserted) {
         
-        KeReleaseDispatcherDatabaseLock(OldIrql);
         return FALSE;
     }
     
@@ -247,7 +210,7 @@
         
         DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode);
         InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
-                   &Apc->ApcListEntry);
+                       &Apc->ApcListEntry);
     }
     
     /* Confirm Insertion */    
@@ -271,9 +234,9 @@
             DPRINT ("Requesting APC Interrupt for Running Thread \n");
             HalRequestSoftwareInterrupt(APC_LEVEL);
             
-        } else if ((Thread->State == THREAD_STATE_BLOCKED) && 
-                 (Thread->WaitIrql < APC_LEVEL) && 
-                 (Apc->NormalRoutine == NULL)) {
+        } else if ((Thread->State == THREAD_STATE_BLOCKED) && (Thread->WaitIrql == PASSIVE_LEVEL) &&
+                   ((Apc->NormalRoutine == NULL) || 
+                   ((!Thread->KernelApcDisable) && (!Thread->ApcState.KernelApcInProgress)))) {
           
             DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n");
             KiAbortWaitThread(Thread, STATUS_KERNEL_APC, PriorityBoost);
@@ -287,10 +250,79 @@
         Thread->ApcState.UserApcPending = TRUE;
         KiAbortWaitThread(Thread, STATUS_USER_APC, PriorityBoost);
     }
+    
+    return TRUE;
+}
+    
+/*++
+ * KeInsertQueueApc 
+ * @implemented NT4
+ *
+ *     The KeInsertQueueApc routine queues a APC for execution when the right
+ *     scheduler environment exists.
+ *
+ * Params:
+ *     Apc - Pointer to an initialized control object of type DPC for which the
+ *           caller provides the storage. 
+ *
+ *     SystemArgument[1,2] - Pointer to a set of two parameters that contain
+ *                           untyped data.
+ *
+ *     PriorityBoost - Priority Boost to apply to the Thread.
+ *
+ * Returns:
+ *     If the APC is already inserted or APC queueing is disabled, FALSE.
+ *     Otherwise, TRUE.
+ *
+ * Remarks:
+ *     The APC will execute at APC_LEVEL for the KernelRoutine registered, and
+ *     at PASSIVE_LEVEL for the NormalRoutine registered.
+ *
+ *     Callers of this routine must be running at IRQL = PASSIVE_LEVEL.
+ *
+ *--*/
+BOOLEAN
+STDCALL
+KeInsertQueueApc(PKAPC Apc,
+                 PVOID SystemArgument1,
+                 PVOID SystemArgument2,
+                 KPRIORITY PriorityBoost)
 
+{
+    KIRQL OldIrql;
+    PKTHREAD Thread;
+    BOOLEAN Inserted;
+   
+    ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
+    DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
+           "SystemArgument2 %x)\n",Apc,SystemArgument1,
+            SystemArgument2);
+
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Get the Thread specified in the APC */
+    Thread = Apc->Thread;
+       
+    /* Make sure the thread allows APC Queues.
+    * The thread is not apc queueable, for instance, when it's (about to be) terminated.
+    */
+    if (Thread->ApcQueueable == FALSE) {
+        DPRINT("Thread doesn't allow APC Queues\n");
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+        return FALSE;
+    }
+    
+    /* Set the System Arguments */
+    Apc->SystemArgument1 = SystemArgument1;
+    Apc->SystemArgument2 = SystemArgument2;
+
+    /* Call the Internal Function */
+    Inserted = KiInsertQueueApc(Apc, PriorityBoost);
+
     /* Return Sucess if we are here */
     KeReleaseDispatcherDatabaseLock(OldIrql);
-    return TRUE;
+    return Inserted;
 }
 
 /*++

Modified: trunk/reactos/ntoskrnl/ke/dpc.c
--- trunk/reactos/ntoskrnl/ke/dpc.c	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/ke/dpc.c	2005-03-18 05:53:04 UTC (rev 14174)
@@ -491,7 +491,7 @@
 
     /* Dispatch the Thread */
     KeLowerIrql(DISPATCH_LEVEL);
-    PsDispatchThread(THREAD_STATE_READY);
+    KiDispatchThread(THREAD_STATE_READY);
 }    
 
 /*

Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c
--- trunk/reactos/ntoskrnl/ke/i386/exp.c	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/ke/i386/exp.c	2005-03-18 05:53:04 UTC (rev 14174)
@@ -582,6 +582,125 @@
 }
 
 VOID
+KeContextToTrapFrame(PCONTEXT Context,
+		     PKTRAP_FRAME TrapFrame)
+{
+   if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+     {
+	TrapFrame->Esp = Context->Esp;
+	TrapFrame->Ss = Context->SegSs;
+	TrapFrame->Cs = Context->SegCs;
+	TrapFrame->Eip = Context->Eip;
+	TrapFrame->Eflags = Context->EFlags;	
+	TrapFrame->Ebp = Context->Ebp;
+     }
+   if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+     {
+	TrapFrame->Eax = Context->Eax;
+	TrapFrame->Ebx = Context->Ebx;
+	TrapFrame->Ecx = Context->Ecx;
+	TrapFrame->Edx = Context->Edx;
+	TrapFrame->Esi = Context->Esi;
+	TrapFrame->Edi = Context->Edi;
+     }
+   if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
+     {
+	TrapFrame->Ds = Context->SegDs;
+	TrapFrame->Es = Context->SegEs;
+	TrapFrame->Fs = Context->SegFs;
+	TrapFrame->Gs = Context->SegGs;
+     }
+   if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
+     {
+	/*
+	 * Not handled
+	 *
+	 * This should be handled separately I think.
+	 *  - blight
+	 */
+     }
+   if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+     {
+	/*
+	 * Not handled
+	 */
+     }
+}
+
+VOID
+KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
+		     PCONTEXT Context)
+{
+   if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+     {
+	Context->SegSs = TrapFrame->Ss;
+	Context->Esp = TrapFrame->Esp;
+	Context->SegCs = TrapFrame->Cs;
+	Context->Eip = TrapFrame->Eip;
+	Context->EFlags = TrapFrame->Eflags;
+	Context->Ebp = TrapFrame->Ebp;
+     }
+   if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+     {
+	Context->Eax = TrapFrame->Eax;
+	Context->Ebx = TrapFrame->Ebx;
+	Context->Ecx = TrapFrame->Ecx;
+	/*
+	 * NOTE: In the trap frame which is built on entry to a system
+	 * call TrapFrame->Edx will actually hold the address of the
+	 * previous TrapFrame. I don't believe leaking this information
+	 * has security implications. Also EDX holds the address of the
+	 * arguments to the system call in progress so it isn't of much
+	 * interest to the debugger.
+	 */
+	Context->Edx = TrapFrame->Edx;
+	Context->Esi = TrapFrame->Esi;
+	Context->Edi = TrapFrame->Edi;
+     }
+   if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
+     {
+	Context->SegDs = TrapFrame->Ds;
+	Context->SegEs = TrapFrame->Es;
+	Context->SegFs = TrapFrame->Fs;
+	Context->SegGs = TrapFrame->Gs;
+     }
+   if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+     {
+	/*
+	 * FIXME: Implement this case
+	 */	
+	Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
+     }
+   if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
+     {
+	/*
+	 * FIXME: Implement this case
+	 *
+	 * I think this should only be filled for FPU exceptions, otherwise I
+         * would not know where to get it from as it can be the current state
+	 * of the FPU or already saved in the thread's FPU save area.
+	 *  -blight
+	 */
+	Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
+     }
+#if 0
+   if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
+     {
+	/*
+	 * FIXME: Investigate this
+	 *
+	 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
+	 * This should only be filled in case of a SIMD exception I think, so
+	 * this is not the right place (like for FPU the state could already be
+	 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
+	 *  -blight
+	 */
+        Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
+     }
+#endif
+}
+
+VOID
 KeDumpStackFrames(PULONG Frame)
 {
 	PULONG StackBase, StackEnd;

Modified: trunk/reactos/ntoskrnl/ke/i386/tskswitch.S
--- trunk/reactos/ntoskrnl/ke/i386/tskswitch.S	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/ke/i386/tskswitch.S	2005-03-18 05:53:04 UTC (rev 14174)
@@ -206,11 +206,6 @@
 
 	call    @KeReleaseDispatcherDatabaseLockFromDpcLevel@0
 
-	cmpl	$0, _PiNrThreadsAwaitingReaping
-	je	5f
-	call	_PiWakeupReaperThread@0
-5:
-
 	/*
 	 * Restore the saved register and exit
 	 */

Modified: trunk/reactos/ntoskrnl/ke/kthread.c
--- trunk/reactos/ntoskrnl/ke/kthread.c	2005-03-18 03:26:12 UTC (rev 14173)
+++ trunk/reactos/ntoskrnl/ke/kthread.c	2005-03-18 05:53:04 UTC (rev 14174)
@@ -15,10 +15,478 @@
 #include <internal/debug.h>
 
 #define THREAD_ALERT_INCREMENT 2
+
+extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
+
+/*
+ * PURPOSE: List of threads associated with each priority level
+ */
+LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
+static ULONG PriorityListMask = 0;
+ULONG IdleProcessorMask = 0;
+extern BOOLEAN DoneInitYet;
+
 /* FUNCTIONS *****************************************************************/
 
+STATIC 
+VOID
+KiRequestReschedule(CCHAR Processor)
+{
+    PKPCR Pcr;
+
+    Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE);
+    Pcr->Prcb->QuantumEnd = TRUE;
+    KiIpiSendRequest(1 << Processor, IPI_REQUEST_DPC);
+}
+
+STATIC 
+VOID
+KiInsertIntoThreadList(KPRIORITY Priority, 
+                       PKTHREAD Thread)
+{
+    ASSERT(THREAD_STATE_READY == Thread->State);
+    ASSERT(Thread->Priority == Priority);
+    
+    if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) {
+        
+        DPRINT1("Invalid thread priority (%d)\n", Priority);
+        KEBUGCHECK(0);
+    }
+    
+    InsertTailList(&PriorityListHead[Priority], &Thread->QueueListEntry);
+    PriorityListMask |= (1 << Priority);
+}
+
+STATIC
+VOID 
+KiRemoveFromThreadList(PKTHREAD Thread)
+{
+    ASSERT(THREAD_STATE_READY == Thread->State);
+    RemoveEntryList(&Thread->QueueListEntry);
+    if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Priority])) {
+        
+        PriorityListMask &= ~(1 << Thread->Priority);
+    }
+}
+
+STATIC
+PKTHREAD 
+KiScanThreadList(KPRIORITY Priority, 
+                 KAFFINITY Affinity)
+{
+    PLIST_ENTRY current_entry;
+    PKTHREAD current;
+    ULONG Mask;
+
+    Mask = (1 << Priority);
+    
+    if (PriorityListMask & Mask) {
+        
+        current_entry = PriorityListHead[Priority].Flink;
+        
+        while (current_entry != &PriorityListHead[Priority]) {
+           
+            current = CONTAINING_RECORD(current_entry, KTHREAD, QueueListEntry);
+            
+            if (current->State != THREAD_STATE_READY) {
+                
+                DPRINT1("%d/%d\n", &current, current->State);
+            }
+            
+            ASSERT(current->State == THREAD_STATE_READY);
+            
+            if (current->Affinity & Affinity) {
+                
+                KiRemoveFromThreadList(current);
+                return(current);
+            }
+            
+            current_entry = current_entry->Flink;
+        }
+    }
+    
+    return(NULL);
+}
+
+VOID 
+STDCALL
+KiDispatchThreadNoLock(ULONG NewThreadStatus)
+{
+    KPRIORITY CurrentPriority;
+    PKTHREAD Candidate;
+    ULONG Affinity;
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+
+    DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
+            CurrentThread, NewThreadStatus, CurrentThread->State);
+
+    CurrentThread->State = (UCHAR)NewThreadStatus;
+    
+    if (NewThreadStatus == THREAD_STATE_READY) {
+            
+        KiInsertIntoThreadList(CurrentThread->Priority,
+                               CurrentThread);
+    }
+
+    Affinity = 1 << KeGetCurrentProcessorNumber();
+    
+    for (CurrentPriority = HIGH_PRIORITY; CurrentPriority >= LOW_PRIORITY; CurrentPriority--) {
+        
+        Candidate = KiScanThreadList(CurrentPriority, Affinity);
+        
+        if (Candidate == CurrentThread) {
+
+            Candidate->State = THREAD_STATE_RUNNING;
+            KeReleaseDispatcherDatabaseLockFromDpcLevel();	
+            return;
+        }
+        
+        if (Candidate != NULL) {
+            
+            PKTHREAD OldThread;
+            PKTHREAD IdleThread;
+
+            DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
+
+            Candidate->State = THREAD_STATE_RUNNING;
+
+            OldThread = CurrentThread;
+            CurrentThread = Candidate;
+            IdleThread = KeGetCurrentPrcb()->IdleThread;
+
+            if (OldThread == IdleThread) {
+                
+                IdleProcessorMask &= ~Affinity;
+                
+            } else if (CurrentThread == IdleThread) {
+                
+                IdleProcessorMask |= Affinity;
+            }
+
+            MmUpdatePageDir(PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
+
+            /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
+            KiArchContextSwitch(CurrentThread, OldThread);
+            return;
+        }
+    }
+    
+    DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
+    KEBUGCHECK(0);
+}
+
+VOID
+STDCALL
+KiBlockThread(PNTSTATUS Status, 
+              UCHAR Alertable, 
+              ULONG WaitMode,
+              UCHAR WaitReason)
+{
+    PKTHREAD Thread = KeGetCurrentThread();
+    PKWAIT_BLOCK WaitBlock;
+
+    if (Thread->ApcState.KernelApcPending) {
+    
+        DPRINT("Dispatching Thread as ready (APC!)\n");
+        
+        /* Remove Waits */
+        WaitBlock = Thread->WaitBlockList;
+        while (WaitBlock) {
+            RemoveEntryList (&WaitBlock->WaitListEntry);
+            WaitBlock = WaitBlock->NextWaitBlock;
+        }
+        Thread->WaitBlockList = NULL;
+        
+        /* Dispatch it and return status */
+        KiDispatchThreadNoLock (THREAD_STATE_READY);
+        if (Status != NULL) *Status = STATUS_KERNEL_APC;
+
+    } else {
+
+        /* Set the Thread Data as Requested */
+        DPRINT("Dispatching Thread as blocked\n");
+        Thread->Alertable = Alertable;
+        Thread->WaitMode = (UCHAR)WaitMode;
+        Thread->WaitReason = WaitReason;
+        
+        /* Dispatch it and return status */
+        KiDispatchThreadNoLock(THREAD_STATE_BLOCKED);
+        if (Status != NULL) *Status = Thread->WaitStatus;
+    }
+    
+    DPRINT("Releasing Dispatcher Lock\n");
+    KfLowerIrql(Thread->WaitIrql);
+}
+
+VOID 
+STDCALL
+KiDispatchThread(ULONG NewThreadStatus)
+{
+    KIRQL OldIrql;
+
+    if (!DoneInitYet || KeGetCurrentPrcb()->IdleThread == NULL) {
+        return;
+    }
+    
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    KiDispatchThreadNoLock(NewThreadStatus);
+    KeLowerIrql(OldIrql);
+}
+
+VOID
+STDCALL
+KiUnblockThread(PKTHREAD Thread, 
+                PNTSTATUS WaitStatus, 
+                KPRIORITY Increment)
+{
+    if (THREAD_STATE_TERMINATED_1 == Thread->State ||
+        THREAD_STATE_TERMINATED_2 == Thread->State) {
[truncated at 1000 lines; 7432 more skipped]