- Invert CONFIG_SMP defines as requested by Hartmut
[reactos.git] / reactos / ntoskrnl / ke / kthread.c
index cd01714..57c775c 100644 (file)
@@ -3,7 +3,7 @@
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/kthread.c
  * PURPOSE:         Microkernel thread support
- * 
+ *
  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
  *                  David Welch (welch@cwcom.net)
  */
 #define NDEBUG
 #include <internal/debug.h>
 
+/* FIXME: NDK */
+#define MAXIMUM_SUSPEND_COUNT 0x7F
 #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 PETHREAD PspReaperList;
+
 /* FUNCTIONS *****************************************************************/
 
+STATIC
+VOID
+KiRequestReschedule(CCHAR Processor)
+{
+    PKPCR Pcr;
+
+    Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE);
+    Pcr->Prcb->QuantumEnd = TRUE;
+    KiIpiSendRequest(1 << Processor, IPI_DPC);
+}
+
+STATIC
+VOID
+KiInsertIntoThreadList(KPRIORITY Priority,
+                       PKTHREAD Thread)
+{
+    ASSERT(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->WaitListEntry);
+    PriorityListMask |= (1 << Priority);
+}
+
+STATIC
+VOID
+KiRemoveFromThreadList(PKTHREAD Thread)
+{
+    ASSERT(Ready == Thread->State);
+    RemoveEntryList(&Thread->WaitListEntry);
+    if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Priority])) {
+
+        PriorityListMask &= ~(1 << Thread->Priority);
+    }
+}
+
+STATIC
+PKTHREAD
+KiScanThreadList(KPRIORITY Priority,
+                 KAFFINITY Affinity)
+{
+    PKTHREAD current;
+    ULONG Mask;
+
+    Mask = (1 << Priority);
+
+    if (PriorityListMask & Mask) {
+
+        LIST_FOR_EACH(current, &PriorityListHead[Priority], KTHREAD, WaitListEntry) {
+
+            if (current->State != Ready) {
+
+                DPRINT1("%d/%d\n", &current, current->State);
+            }
+
+            ASSERT(current->State == Ready);
+
+            if (current->Affinity & Affinity) {
+
+                KiRemoveFromThreadList(current);
+                return(current);
+            }
+        }
+    }
+
+    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 == 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 = Running;
+            KeReleaseDispatcherDatabaseLockFromDpcLevel();
+            return;
+        }
+
+        if (Candidate != NULL) {
+
+            PKTHREAD OldThread;
+            PKTHREAD IdleThread;
+
+            DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
+
+            Candidate->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 */
+            DPRINT("You are : %x, swapping to: %x\n", OldThread, CurrentThread);
+            KiArchContextSwitch(CurrentThread);
+            DPRINT("You are : %x, swapped from: %x\n", OldThread, CurrentThread);
+            return;
+        }
+    }
+
+    DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
+    KEBUGCHECK(0);
+}
+
+NTSTATUS
+NTAPI
+KiSwapThread(VOID)
+{
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+
+    /* Find a new thread to run */
+    DPRINT("Dispatching Thread as blocked\n");
+    KiDispatchThreadNoLock(Waiting);
+
+    /* Lower IRQL back */
+    DPRINT("Lowering IRQL \n");
+    KfLowerIrql(CurrentThread->WaitIrql);
+
+    /* Return the wait status */
+    return CurrentThread->WaitStatus;
+}
+
+VOID
+STDCALL
+KiDispatchThread(ULONG NewThreadStatus)
+{
+    KIRQL OldIrql;
+
+    if (KeGetCurrentPrcb()->IdleThread == NULL) {
+        return;
+    }
+
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    KiDispatchThreadNoLock(NewThreadStatus);
+    KeLowerIrql(OldIrql);
+}
+
+VOID
+STDCALL
+KiUnblockThread(PKTHREAD Thread,
+                PNTSTATUS WaitStatus,
+                KPRIORITY Increment)
+{
+    if (Terminated == Thread->State) {
+
+        DPRINT("Can't unblock thread 0x%x because it's terminating\n",
+               Thread);
+
+    } else if (Ready == Thread->State ||
+               Running == Thread->State) {
+
+        DPRINT("Can't unblock thread 0x%x because it's %s\n",
+               Thread, (Thread->State == Ready ? "ready" : "running"));
+
+    } else {
+
+        LONG Processor;
+        KAFFINITY Affinity;
+
+        /* FIXME: This propably isn't the right way to do it... */
+        /* No it's not... i'll fix it later-- Alex */
+        if (Thread->Priority < LOW_REALTIME_PRIORITY &&
+            Thread->BasePriority < LOW_REALTIME_PRIORITY - 2) {
+
+            if (!Thread->PriorityDecrement && !Thread->DisableBoost) {
+
+                Thread->Priority = Thread->BasePriority + Increment;
+                Thread->PriorityDecrement = Increment;
+            }
+
+            /* Also decrease quantum */
+            Thread->Quantum--;
+
+        } else {
+
+            Thread->Quantum = Thread->QuantumReset;
+        }
+
+        if (WaitStatus != NULL) {
+
+            Thread->WaitStatus = *WaitStatus;
+        }
+
+        Thread->State = Ready;
+        KiInsertIntoThreadList(Thread->Priority, Thread);
+        Processor = KeGetCurrentProcessorNumber();
+        Affinity = Thread->Affinity;
+
+        if (!(IdleProcessorMask & (1 << Processor) & Affinity) &&
+             (IdleProcessorMask & ~(1 << Processor) & Affinity)) {
+
+            LONG i;
+
+            for (i = 0; i < KeNumberProcessors - 1; i++) {
+
+                Processor++;
+
+                if (Processor >= KeNumberProcessors) {
+
+                    Processor = 0;
+                }
+
+                if (IdleProcessorMask & (1 << Processor) & Affinity) {
+#if 0
+                    /* FIXME:
+                     *   Reschedule the threads on an other processor
+                     */
+                    KeReleaseDispatcherDatabaseLockFromDpcLevel();
+                    KiRequestReschedule(Processor);
+                    KeAcquireDispatcherDatabaseLockAtDpcLevel();
+#endif
+                    break;
+                }
+            }
+        }
+    }
+}
+
+VOID
+STDCALL
+KiAdjustQuantumThread(IN PKTHREAD Thread)
+{
+    KPRIORITY Priority;
+
+    /* Don't adjust for RT threads */
+    if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
+        Thread->BasePriority < LOW_REALTIME_PRIORITY - 2)
+    {
+        /* Decrease Quantum by one and see if we've ran out */
+        if (--Thread->Quantum <= 0)
+        {
+            /* Return quantum */
+            Thread->Quantum = Thread->QuantumReset;
+
+            /* Calculate new Priority */
+            Priority = Thread->Priority - (Thread->PriorityDecrement + 1);
+
+            /* Normalize it if we've gone too low */
+            if (Priority < Thread->BasePriority) Priority = Thread->BasePriority;
+
+            /* Reset the priority decrement, we've done it */
+            Thread->PriorityDecrement = 0;
+
+            /* Set the new priority, if needed */
+            if (Priority != Thread->Priority)
+            {
+                /* 
+                 * FIXME: This should be a call to KiSetPriorityThread but
+                 * due to the current ""scheduler"" in ROS, it can't be done
+                 * cleanly since it actualyl dispatches threads instead.
+                 */
+                Thread->Priority = Priority;
+            }
+            else
+            {
+                /* FIXME: Priority hasn't changed, find a new thread */
+            }
+        }
+    }
+
+    /* Nothing to do... */
+    return;
+}
+
+
+VOID
+STDCALL
+KiSuspendThreadKernelRoutine(PKAPC Apc,
+                             PKNORMAL_ROUTINE* NormalRoutine,
+                             PVOID* NormalContext,
+                             PVOID* SystemArgument1,
+                             PVOID* SystemArguemnt2)
+{
+}
+
+VOID
+STDCALL
+KiSuspendThreadNormalRoutine(PVOID NormalContext,
+                             PVOID SystemArgument1,
+                             PVOID SystemArgument2)
+{
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+
+    /* Non-alertable kernel-mode suspended wait */
+    DPRINT("Waiting...\n");
+    KeWaitForSingleObject(&CurrentThread->SuspendSemaphore,
+                          Suspended,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+    DPRINT("Done Waiting\n");
+}
+
+#ifdef KeGetCurrentThread
+#undef KeGetCurrentThread
+#endif
+/*
+ * @implemented
+ */
+PKTHREAD
+STDCALL
+KeGetCurrentThread(VOID)
+{
+#ifdef CONFIG_SMP
+    ULONG Flags;
+    PKTHREAD Thread;
+    Ke386SaveFlags(Flags);
+    Ke386DisableInterrupts();
+    Thread = KeGetCurrentPrcb()->CurrentThread;
+    Ke386RestoreFlags(Flags);
+    return Thread;
+#else
+    return(KeGetCurrentPrcb()->CurrentThread);
+#endif
+}
+
+VOID
+STDCALL
+KeSetPreviousMode(ULONG Mode)
+{
+    PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
+}
+
+/*
+ * @implemented
+ */
+KPROCESSOR_MODE
+STDCALL
+KeGetPreviousMode(VOID)
+{
+    return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
+}
+
+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;
+}
+
+VOID
+STDCALL
+KeRundownThread(VOID)
+{
+    KIRQL OldIrql;
+    PKTHREAD Thread = KeGetCurrentThread();
+    PLIST_ENTRY NextEntry, ListHead;
+    PKMUTANT Mutant;
+    DPRINT("KeRundownThread: %x\n", Thread);
+
+    /* Optimized path if nothing is on the list at the moment */
+    if (IsListEmpty(&Thread->MutantListHead)) return;
+
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Get the List Pointers */
+    ListHead = &Thread->MutantListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the Mutant */
+        Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry);
+        DPRINT1("Mutant: %p. Type, Size %x %x\n",
+                 Mutant,
+                 Mutant->Header.Type,
+                 Mutant->Header.Size);
+
+        /* Make sure it's not terminating with APCs off */
+        if (Mutant->ApcDisable)
+        {
+            /* Bugcheck the system */
+            KEBUGCHECKEX(0,//THREAD_TERMINATE_HELD_MUTEX,
+                         (ULONG_PTR)Thread,
+                         (ULONG_PTR)Mutant,
+                         0,
+                         0);
+        }
+
+        /* Now we can remove it */
+        RemoveEntryList(&Mutant->MutantListEntry);
+
+        /* Unconditionally abandon it */
+        DPRINT("Abandonning the Mutant\n");
+        Mutant->Header.SignalState = 1;
+        Mutant->Abandoned = TRUE;
+        Mutant->OwnerThread = NULL;
+
+        /* Check if the Wait List isn't empty */
+        DPRINT("Checking whether to wake the Mutant\n");
+        if (!IsListEmpty(&Mutant->Header.WaitListHead))
+        {
+            /* Wake the Mutant */
+            DPRINT("Waking the Mutant\n");
+            KiWaitTest(&Mutant->Header, MUTANT_INCREMENT);
+        }
+
+        /* Move on */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Release the Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+}
+
+ULONG
+STDCALL
+KeResumeThread(PKTHREAD Thread)
+{
+    ULONG PreviousCount;
+    KIRQL OldIrql;
+
+    DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread,
+            Thread->SuspendCount, Thread->FreezeCount);
+
+    /* Lock the Dispatcher */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Save the Old Count */
+    PreviousCount = Thread->SuspendCount;
+
+    /* Check if it existed */
+    if (PreviousCount) {
+
+        Thread->SuspendCount--;
+
+        /* Decrease the current Suspend Count and Check Freeze Count */
+        if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) {
+
+            /* Signal the Suspend Semaphore */
+            Thread->SuspendSemaphore.Header.SignalState++;
+            KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
+        }
+    }
+
+    /* Release Lock and return the Old State */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return PreviousCount;
+}
+
+VOID
+FASTCALL
+KiInsertQueueApc(PKAPC Apc,
+                 KPRIORITY PriorityBoost);
+
+/*
+ * Used by the debugging code to freeze all the process's threads
+ * while the debugger is examining their state.
+ */
+VOID
+STDCALL
+KeFreezeAllThreads(PKPROCESS Process)
+{
+    KIRQL OldIrql;
+    PKTHREAD Current;
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+
+    /* Acquire Lock */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* If someone is already trying to free us, try again */
+    while (CurrentThread->FreezeCount)
+    {
+        /* Release and re-acquire the lock so the APC will go through */
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+        OldIrql = KeAcquireDispatcherDatabaseLock();
+    }
+
+    /* Enter a critical region */
+    KeEnterCriticalRegion();
+
+    /* Loop the Process's Threads */
+    LIST_FOR_EACH(Current, &Process->ThreadListHead, KTHREAD, ThreadListEntry)
+    {
+        /* Make sure it's not ours */
+        if (Current != CurrentThread)
+        {
+            /* Should be bother inserting the APC? */
+            if (Current->ApcQueueable)
+            {
+                /* Make sure it wasn't already frozen, and that it's not suspended */
+                if (!(++Current->FreezeCount) && !(Current->SuspendCount))
+                {
+                    /* Did we already insert it? */
+                    if (!Current->SuspendApc.Inserted)
+                    {
+                        /* Insert the APC */
+                        Current->SuspendApc.Inserted = TRUE;
+                        KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
+                    }
+                    else
+                    {
+                        /* Unsignal the Semaphore, the APC already got inserted */
+                        Current->SuspendSemaphore.Header.SignalState--;
+                    }
+                }
+            }
+        }
+    }
+
+    /* Release the lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+}
+
+NTSTATUS
+STDCALL
+KeSuspendThread(PKTHREAD Thread)
+{
+    ULONG PreviousCount;
+    KIRQL OldIrql;
+
+    DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread, Thread->SuspendCount, Thread->FreezeCount);
+
+    /* Lock the Dispatcher */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Save the Old Count */
+    PreviousCount = Thread->SuspendCount;
+
+    /* Handle the maximum */
+    if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
+    {
+        /* Raise an exception */
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+        RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
+    }
+
+    /* Should we bother to queue at all? */
+    if (Thread->ApcQueueable)
+    {
+        /* Increment the suspend count */
+        Thread->SuspendCount++;
+
+        /* Check if we should suspend it */
+        if (!PreviousCount && !Thread->FreezeCount)
+        {
+            /* Is the APC already inserted? */
+            if (!Thread->SuspendApc.Inserted)
+            {
+                /* Not inserted, insert it */
+                Thread->SuspendApc.Inserted = TRUE;
+                KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
+            }
+            else
+            {
+                /* Unsignal the Semaphore, the APC already got inserted */
+                Thread->SuspendSemaphore.Header.SignalState--;
+            }
+        }
+    }
+
+    /* Release Lock and return the Old State */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return PreviousCount;
+}
+
+ULONG
+STDCALL
+KeForceResumeThread(IN PKTHREAD Thread)
+{
+    KIRQL OldIrql;
+    ULONG PreviousCount;
+
+    /* Lock the Dispatcher Database and the APC Queue */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Save the old Suspend Count */
+    PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
+
+    /* If the thread is suspended, wake it up!!! */
+    if (PreviousCount) {
+
+        /* Unwait it completely */
+        Thread->SuspendCount = 0;
+        Thread->FreezeCount = 0;
+
+        /* Signal and satisfy */
+        Thread->SuspendSemaphore.Header.SignalState++;
+        KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
+    }
+
+    /* Release Lock and return the Old State */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return PreviousCount;
+}
+
 ULONG
 STDCALL
 KeAlertResumeThread(IN PKTHREAD Thread)
@@ -25,36 +678,36 @@ KeAlertResumeThread(IN PKTHREAD Thread)
     KIRQL OldIrql;
 
     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
-   
+
     /* Lock the Dispatcher Database and the APC Queue */
     OldIrql = KeAcquireDispatcherDatabaseLock();
     KiAcquireSpinLock(&Thread->ApcQueueLock);
 
     /* Return if Thread is already alerted. */
     if (Thread->Alerted[KernelMode] == FALSE) {
-       
+
         /* If it's Blocked, unblock if it we should */
-        if (Thread->State == THREAD_STATE_BLOCKED &&  Thread->Alertable) {
-            
+        if (Thread->State == Waiting &&  Thread->Alertable) {
+
             DPRINT("Aborting Wait\n");
             KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
-       
+
         } else {
-           
+
             /* If not, simply Alert it */
             Thread->Alerted[KernelMode] = TRUE;
         }
     }
-    
+
     /* Save the old Suspend Count */
-    PreviousCount = Thread->SuspendCount;    
-    
+    PreviousCount = Thread->SuspendCount;
+
     /* If the thread is suspended, decrease one of the suspend counts */
     if (PreviousCount) {
-            
+
         /* Decrease count. If we are now zero, unwait it completely */
         if (--Thread->SuspendCount) {
-            
+
             /* Signal and satisfy */
             Thread->SuspendSemaphore.Header.SignalState++;
             KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
@@ -69,7 +722,7 @@ KeAlertResumeThread(IN PKTHREAD Thread)
 
 BOOLEAN
 STDCALL
-KeAlertThread(PKTHREAD Thread, 
+KeAlertThread(PKTHREAD Thread,
               KPROCESSOR_MODE AlertMode)
 {
     KIRQL OldIrql;
@@ -77,31 +730,31 @@ KeAlertThread(PKTHREAD Thread,
 
     /* Acquire the Dispatcher Database Lock */
     OldIrql = KeAcquireDispatcherDatabaseLock();
-   
+
     /* Save the Previous State */
     PreviousState = Thread->Alerted[AlertMode];
-      
+
     /* Return if Thread is already alerted. */
     if (PreviousState == FALSE) {
-       
+
         /* If it's Blocked, unblock if it we should */
-        if (Thread->State == THREAD_STATE_BLOCKED && 
+        if (Thread->State == Waiting &&
             (AlertMode == KernelMode || Thread->WaitMode == AlertMode) &&
             Thread->Alertable) {
-            
+
             DPRINT("Aborting Wait\n");
             KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
-       
+
         } else {
-           
+
             /* If not, simply Alert it */
             Thread->Alerted[AlertMode] = TRUE;
         }
     }
-    
+
     /* Release the Dispatcher Lock */
     KeReleaseDispatcherDatabaseLock(OldIrql);
-    
+
     /* Return the old state */
     return PreviousState;
 }
@@ -127,217 +780,117 @@ KeCapturePersistentThreadState(IN PVOID CurrentThread,
  */
 VOID
 STDCALL
-KeInitializeThread(PKPROCESS Process, 
-                   PKTHREAD Thread, 
-                   BOOLEAN First)
+KeInitializeThread(PKPROCESS Process,
+                   PKTHREAD Thread,
+                   PKSYSTEM_ROUTINE SystemRoutine,
+                   PKSTART_ROUTINE StartRoutine,
+                   PVOID StartContext,
+                   PCONTEXT Context,
+                   PVOID Teb,
+                   PVOID KernelStack)
 {
-    PVOID KernelStack;
-    NTSTATUS Status;
-    extern unsigned int init_stack_top;
-    extern unsigned int init_stack;
-    PMEMORY_AREA StackArea;
-    ULONG i;
-    PHYSICAL_ADDRESS BoundaryAddressMultiple;
-  
-    /* Initialize the Boundary Address */
-    BoundaryAddressMultiple.QuadPart = 0;
-  
     /* Initalize the Dispatcher Header */
+    DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread, Process);
     KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
                                  ThreadObject,
-                                 sizeof(KTHREAD),
+                                 sizeof(KTHREAD) / sizeof(LONG),
                                  FALSE);
-    InitializeListHead(&Thread->MutantListHead);
-    
-    /* If this is isn't the first thread, allocate the Kernel Stack */
-    if (!First) {
-        
-        PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
-        KernelStack = NULL;
-      
-        MmLockAddressSpace(MmGetKernelAddressSpace());
-        Status = MmCreateMemoryArea(NULL,
-                                    MmGetKernelAddressSpace(),
-                                    MEMORY_AREA_KERNEL_STACK,
-                                    &KernelStack,
-                                    MM_STACK_SIZE,
-                                    0,
-                                    &StackArea,
-                                    FALSE,
-                                    FALSE,
-                                    BoundaryAddressMultiple);
-        MmUnlockAddressSpace(MmGetKernelAddressSpace());
-      
-        /* Check for Success */
-        if (!NT_SUCCESS(Status)) {
-            
-            DPRINT1("Failed to create thread stack\n");
-            KEBUGCHECK(0);
-        }
-        
-        /* Mark the Stack */
-        for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) {
 
-            Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
-            
-            /* Check for success */
-            if (!NT_SUCCESS(Status)) {
-                
-                KEBUGCHECK(0);
-            }
-        }
-        
-        /* Create a Virtual Mapping for it */
-        Status = MmCreateVirtualMapping(NULL,
-                                        KernelStack,
-                                        PAGE_READWRITE,
-                                        Page,
-                                        MM_STACK_SIZE / PAGE_SIZE);
-        
-        /* Check for success */
-        if (!NT_SUCCESS(Status)) {
-            
-            KEBUGCHECK(0);
-        }
-        
-        /* Set the Kernel Stack */
-        Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
-        Thread->StackBase    = (PCHAR)KernelStack + MM_STACK_SIZE;
-        Thread->StackLimit   = (ULONG_PTR)KernelStack;
-        Thread->KernelStack  = (PCHAR)KernelStack + MM_STACK_SIZE;
-        
-    } else {
-        
-        /* Use the Initial Stack */
-        Thread->InitialStack = (PCHAR)init_stack_top;
-        Thread->StackBase = (PCHAR)init_stack_top;
-        Thread->StackLimit = (ULONG_PTR)init_stack;
-        Thread->KernelStack = (PCHAR)init_stack_top;
-    }
+    DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
+            SystemRoutine, StartRoutine, StartContext);
+    DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context, Teb);
 
-    /* 
-     * Establish the pde's for the new stack and the thread structure within the 
-     * address space of the new process. They are accessed while taskswitching or
-     * while handling page faults. At this point it isn't possible to call the 
-     * page fault handler for the missing pde's. 
-     */
-    MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
-    MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
+    /* Initialize the Mutant List */
+    InitializeListHead(&Thread->MutantListHead);
+
+    /* Setup the Service Descriptor Table for Native Calls */
+    Thread->ServiceTable = KeServiceDescriptorTable;
 
-    /* Set the Thread to initalized */
-    Thread->State = THREAD_STATE_INITIALIZED;
-    
-    /* The Native API function will initialize the TEB field later */
-    Thread->Teb = NULL;
-    
-    /* Initialize stuff to zero */
-    Thread->TlsArray = NULL;
-    Thread->DebugActive = 0;
-    Thread->Alerted[0] = 0;
-    Thread->Alerted[1] = 0;
-    Thread->Iopl = 0;
-    
-    /* Set up FPU/NPX Stuff */
-    Thread->NpxState = NPX_STATE_INVALID;
-    Thread->NpxIrql = 0;
-   
     /* Setup APC Fields */
     InitializeListHead(&Thread->ApcState.ApcListHead[0]);
     InitializeListHead(&Thread->ApcState.ApcListHead[1]);
     Thread->ApcState.Process = Process;
-    Thread->ApcState.KernelApcInProgress = 0;
-    Thread->ApcState.KernelApcPending = 0;
-    Thread->ApcState.UserApcPending = 0;
     Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
     Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
     Thread->ApcStateIndex = OriginalApcEnvironment;
-    Thread->ApcQueueable = TRUE;
-    RtlZeroMemory(&Thread->SavedApcState, sizeof(KAPC_STATE));
     KeInitializeSpinLock(&Thread->ApcQueueLock);
-    
-    /* Setup Wait Fields */
-    Thread->WaitStatus = STATUS_SUCCESS;
-    Thread->WaitIrql = PASSIVE_LEVEL;
-    Thread->WaitMode = 0;
-    Thread->WaitNext = FALSE;
-    Thread->WaitListEntry.Flink = NULL;
-    Thread->WaitListEntry.Blink = NULL;
-    Thread->WaitTime = 0;
-    Thread->WaitBlockList = NULL;
-    RtlZeroMemory(Thread->WaitBlock, sizeof(KWAIT_BLOCK) * 4);
-    RtlZeroMemory(&Thread->Timer, sizeof(KTIMER));
+
+    /* Initialize the Suspend APC */
+    KeInitializeApc(&Thread->SuspendApc,
+                    Thread,
+                    OriginalApcEnvironment,
+                    KiSuspendThreadKernelRoutine,
+                    NULL,
+                    KiSuspendThreadNormalRoutine,
+                    KernelMode,
+                    NULL);
+
+    /* Initialize the Suspend Semaphore */
+    KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
+
+    /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
+#if 0
+    Thread->WaitBlock[3].Object = (PVOID)&Thread->Timer;
+    Thread->WaitBlock[3].Thread = Thread;
+    Thread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
+    Thread->WaitBlock[3].WaitType = WaitAny;
+    Thread->WaitBlock[3].NextWaitBlock = NULL;
+    InsertTailList(&Thread->Timer.Header.WaitListHead,
+                   &Thread->WaitBlock[3].WaitListEntry);
+#endif
     KeInitializeTimer(&Thread->Timer);
-    
-    /* Setup scheduler Fields */
+
+    /* Set the TEB */
+    Thread->Teb = Teb;
+
+    /* Set the Thread Stacks */
+    Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
+    Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE;
+    Thread->StackLimit = (ULONG_PTR)KernelStack;
+    Thread->KernelStackResident = TRUE;
+
+    /*
+     * Establish the pde's for the new stack and the thread structure within the
+     * address space of the new process. They are accessed while taskswitching or
+     * while handling page faults. At this point it isn't possible to call the
+     * page fault handler for the missing pde's.
+     */
+    MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
+    MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
+
+    /* Initalize the Thread Context */
+    DPRINT("Initializing the Context for the thread: %x\n", Thread);
+    KiArchInitThreadWithContext(Thread,
+                                SystemRoutine,
+                                StartRoutine,
+                                StartContext,
+                                Context);
+
+    /* Setup scheduler Fields based on Parent */
+    DPRINT("Thread context created, setting Scheduler Data\n");
     Thread->BasePriority = Process->BasePriority;
-    Thread->DecrementCount = 0;
-    Thread->PriorityDecrement = 0;
-    Thread->Quantum = Process->ThreadQuantum;
-    Thread->Saturation = 0;
-    Thread->Priority = Process->BasePriority; 
-    Thread->UserAffinity = Process->Affinity;
-    Thread->SystemAffinityActive = 0;
+    Thread->Quantum = Process->QuantumReset;
+    Thread->QuantumReset = Process->QuantumReset;
     Thread->Affinity = Process->Affinity;
-    Thread->Preempted = 0;
-    Thread->ProcessReadyQueue = 0;
-    Thread->KernelStackResident = 1;
-    Thread->NextProcessor = 0;
-    Thread->ContextSwitches = 0;
-    
-    /* Setup Queue Fields */
-    Thread->Queue = NULL;
-    Thread->QueueListEntry.Flink = NULL;
-    Thread->QueueListEntry.Blink = NULL;
-
-    /* Setup Misc Fields */
-    Thread->LegoData = 0; 
-    Thread->PowerState = 0;
-    Thread->ServiceTable = KeServiceDescriptorTable;
-    Thread->CallbackStack = NULL;
-    Thread->Win32Thread = NULL;
-    Thread->TrapFrame = NULL;
-    Thread->EnableStackSwap = 0;
-    Thread->LargeStack = 0;
-    Thread->ResourceIndex = 0;
-    Thread->PreviousMode = KernelMode;
-    Thread->KernelTime = 0;
-    Thread->UserTime = 0;
+    Thread->Priority = Process->BasePriority;
+    Thread->UserAffinity = Process->Affinity;
+    Thread->DisableBoost = Process->DisableBoost;
     Thread->AutoAlignment = Process->AutoAlignment;
-   
-  /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
-#if 0
-  Thread->WaitBlock[3].Object = (PVOID)&Thread->Timer;
-  Thread->WaitBlock[3].Thread = Thread;
-  Thread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
-  Thread->WaitBlock[3].WaitType = WaitAny;
-  Thread->WaitBlock[3].NextWaitBlock = NULL;
-  InsertTailList(&Thread->Timer.Header.WaitListHead,
-                 &Thread->WaitBlock[3].WaitListEntry);
-#endif
+    Thread->Iopl = Process->Iopl;
 
-    /* Initialize the Suspend APC */  
-    KeInitializeApc(&Thread->SuspendApc,
-                    Thread,
-                    OriginalApcEnvironment,
-                    PiSuspendThreadKernelRoutine,
-                    PiSuspendThreadRundownRoutine,
-                    PiSuspendThreadNormalRoutine,
-                    KernelMode,
-                    NULL);
-     
-    /* Initialize the Suspend Semaphore */
-    KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
-    
-    /* Insert the Thread into the Process's Thread List */
+    /* Set the Thread to initalized */
+    Thread->State = Initialized;
+
+    /*
+     * Insert the Thread into the Process's Thread List
+     * Note, this is the KTHREAD Thread List. It is removed in
+     * ke/kthread.c!KeTerminateThread.
+     */
     InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
-  
-    /* Set up the Suspend Counts */
-    Thread->FreezeCount = 0;
-    Thread->SuspendCount = 0;
-   
-    /* Do x86 specific part */
+    DPRINT("Thread initalized\n");
 }
 
+
 /*
  * @implemented
  */
@@ -358,52 +911,11 @@ KeQueryRuntimeThread(IN PKTHREAD Thread,
 {
     /* Return the User Time */
     *UserTime = Thread->UserTime;
-    
+
     /* Return the Kernel Time */
     return Thread->KernelTime;
 }
 
-VOID
-KeFreeStackPage(PVOID Context, 
-                MEMORY_AREA* MemoryArea, 
-                PVOID Address, 
-                PFN_TYPE Page, 
-                SWAPENTRY SwapEntry, 
-                BOOLEAN Dirty)
-{
-    ASSERT(SwapEntry == 0);
-    if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
-}
-
-NTSTATUS
-KeReleaseThread(PKTHREAD Thread)
-/*
- * FUNCTION: Releases the resource allocated for a thread by
- * KeInitializeThread
- * NOTE: The thread had better not be running when this is called
- */
-{
-  extern unsigned int init_stack;
-
-  /* FIXME - lock the process */
-  RemoveEntryList(&Thread->ThreadListEntry);
-  
-  if (Thread->StackLimit != (ULONG_PTR)init_stack)
-    {       
-      MmLockAddressSpace(MmGetKernelAddressSpace());
-      MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
-                            (PVOID)Thread->StackLimit,
-                            KeFreeStackPage,
-                            NULL);
-      MmUnlockAddressSpace(MmGetKernelAddressSpace());
-    }
-  Thread->StackLimit = 0;
-  Thread->InitialStack = NULL;
-  Thread->StackBase = NULL;
-  Thread->KernelStack = NULL;
-  return(STATUS_SUCCESS);
-}
-
 /*
  * @implemented
  */
@@ -414,7 +926,7 @@ KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
     PKTHREAD Thread = KeGetCurrentThread();
     BOOLEAN PreviousState;
     KIRQL OldIrql;
+
      /* Lock the Dispatcher Database */
     OldIrql = KeAcquireDispatcherDatabaseLock();
 
@@ -426,7 +938,7 @@ KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
 
     /* No, Release Lock */
     KeReleaseDispatcherDatabaseLock(OldIrql);
-        
+
     /* Return Old State */
     return PreviousState;
 }
@@ -442,7 +954,7 @@ KeRevertToUserAffinityThread(VOID)
     KIRQL OldIrql;
 
     ASSERT(CurrentThread->SystemAffinityActive != FALSE);
-        
+
     /* Lock the Dispatcher Database */
     OldIrql = KeAcquireDispatcherDatabaseLock();
 
@@ -451,18 +963,18 @@ KeRevertToUserAffinityThread(VOID)
 
     /* Disable System Affinity */
     CurrentThread->SystemAffinityActive = FALSE;
-    
+
     /* Check if we need to Dispatch a New thread */
     if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) {
-        
+
         /* No, just release */
         KeReleaseDispatcherDatabaseLock(OldIrql);
-    
+
     } else {
-        
+
         /* We need to dispatch a new thread */
         CurrentThread->WaitIrql = OldIrql;
-        PsDispatchThreadNoLock(THREAD_STATE_READY);
+        KiDispatchThreadNoLock(Ready);
         KeLowerIrql(OldIrql);
     }
 }
@@ -477,7 +989,7 @@ KeSetIdealProcessorThread(IN PKTHREAD Thread,
 {
     CCHAR PreviousIdealProcessor;
     KIRQL OldIrql;
-    
+
     /* Lock the Dispatcher Database */
     OldIrql = KeAcquireDispatcherDatabaseLock();
 
@@ -486,10 +998,10 @@ KeSetIdealProcessorThread(IN PKTHREAD Thread,
 
     /* Set New Ideal Processor */
     Thread->IdealProcessor = Processor;
-    
+
     /* Release Lock */
-    KeReleaseDispatcherDatabaseLock(OldIrql);   
-    
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+
     /* Return Old Ideal Processor */
     return PreviousIdealProcessor;
 }
@@ -505,7 +1017,7 @@ KeSetSystemAffinityThread(IN KAFFINITY Affinity)
     KIRQL OldIrql;
 
     ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
-        
+
     /* Lock the Dispatcher Database */
     OldIrql = KeAcquireDispatcherDatabaseLock();
 
@@ -514,20 +1026,342 @@ KeSetSystemAffinityThread(IN KAFFINITY Affinity)
 
     /* Enable System Affinity */
     CurrentThread->SystemAffinityActive = TRUE;
-    
+
     /* Check if we need to Dispatch a New thread */
     if (Affinity & (1 << KeGetCurrentProcessorNumber())) {
-        
+
         /* No, just release */
         KeReleaseDispatcherDatabaseLock(OldIrql);
-    
+
     } else {
-        
+
         /* We need to dispatch a new thread */
         CurrentThread->WaitIrql = OldIrql;
-        PsDispatchThreadNoLock(THREAD_STATE_READY);
+        KiDispatchThreadNoLock(Ready);
+        KeLowerIrql(OldIrql);
+    }
+}
+
+LONG
+STDCALL
+KeQueryBasePriorityThread(IN PKTHREAD Thread)
+{
+    LONG BasePriorityIncrement;
+    KIRQL OldIrql;
+    PKPROCESS Process;
+
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Get the Process */
+    Process = Thread->ApcStatePointer[0]->Process;
+
+    /* Calculate the BPI */
+    BasePriorityIncrement = Thread->BasePriority - Process->BasePriority;
+
+    /* If saturation occured, return the SI instead */
+    if (Thread->Saturation) BasePriorityIncrement = (HIGH_PRIORITY + 1) / 2 *
+                                                    Thread->Saturation;
+
+    /* Release Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+
+    /* Return Increment */
+    return BasePriorityIncrement;
+}
+
+VOID
+STDCALL
+KiSetPriorityThread(PKTHREAD Thread,
+                    KPRIORITY Priority,
+                    PBOOLEAN Released)
+{
+    KPRIORITY OldPriority = Thread->Priority;
+    ULONG Mask;
+    int i;
+    PKPCR Pcr;
+    DPRINT("Changing prio to : %lx\n", Priority);
+
+    /* Check if priority changed */
+    if (OldPriority != Priority)
+    {
+        /* Set it */
+        Thread->Priority = Priority;
+
+        /* Choose action based on thread's state */
+        if (Thread->State == Ready)
+        {
+            /* Remove it from the current queue */
+            KiRemoveFromThreadList(Thread);
+            
+            /* Re-insert it at its current priority */
+            KiInsertIntoThreadList(Priority, Thread);
+
+            /* Check if the old priority was lower */
+            if (KeGetCurrentThread()->Priority < Priority)
+            {
+                /* Dispatch it immediately */
+                KiDispatchThreadNoLock(Ready);
+                *Released = TRUE;
+                return;
+            }
+        }
+        else if (Thread->State == Running)
+        {
+            /* Check if the new priority is lower */
+            if (Priority < OldPriority)
+            {
+                /* Check for threads with a higher priority */
+                Mask = ~((1 << (Priority + 1)) - 1);
+                if (PriorityListMask & Mask)
+                {
+                    /* Found a thread, is it us? */
+                    if (Thread == KeGetCurrentThread())
+                    {
+                        /* Dispatch us */
+                        KiDispatchThreadNoLock(Ready);
+                        *Released = TRUE;
+                        return;
+                    } 
+                    else
+                    {
+                        /* Loop every CPU */
+                        for (i = 0; i < KeNumberProcessors; i++)
+                        {
+                            /* Get the PCR for this CPU */
+                            Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
+
+                            /* Reschedule if the new one is already on a CPU */
+                            if (Pcr->Prcb->CurrentThread == Thread)
+                            {
+                                KeReleaseDispatcherDatabaseLockFromDpcLevel();
+                                KiRequestReschedule(i);
+                                *Released = TRUE;
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* Return to caller */
+    return;
+}
+
+/*
+ * @implemented
+ */
+LONG
+STDCALL
+KeSetBasePriorityThread(PKTHREAD Thread,
+                        LONG Increment)
+{
+    KIRQL OldIrql;
+    PKPROCESS Process;
+    KPRIORITY Priority;
+    KPRIORITY CurrentBasePriority;
+    KPRIORITY BasePriority;
+    BOOLEAN Released = FALSE;
+    LONG CurrentIncrement;
+       
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Get the process and calculate current BP and BPI */
+    Process = Thread->ApcStatePointer[0]->Process;
+    CurrentBasePriority = Thread->BasePriority;
+    CurrentIncrement = CurrentBasePriority - Process->BasePriority;
+
+    /* Change to use the SI if Saturation was used */
+    if (Thread->Saturation) CurrentIncrement = (HIGH_PRIORITY + 1) / 2 *
+                                               Thread->Saturation;
+
+    /* Now check if saturation is being used for the new value */
+    if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
+    {
+        /* Check if we need positive or negative saturation */
+        Thread->Saturation = (Increment > 0) ? 1 : -1;
+    }
+
+    /* Normalize the Base Priority */
+    BasePriority = Process->BasePriority + Increment;
+    if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
+    {
+        /* Check if it's too low */
+        if (BasePriority < LOW_REALTIME_PRIORITY)
+            BasePriority = LOW_REALTIME_PRIORITY;
+
+        /* Check if it's too high */
+        if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
+
+        /* We are at RTP, so use the raw BP */
+        Priority = BasePriority;
+    }
+    else
+    {
+        /* Check if it's entering RTP */
+        if (BasePriority >= LOW_REALTIME_PRIORITY)
+            BasePriority = LOW_REALTIME_PRIORITY - 1;
+
+        /* Check if it's too low */
+        if (BasePriority <= LOW_PRIORITY)
+            BasePriority = 1;
+
+        /* If Saturation is used, then use the raw BP */
+        if (Thread->Saturation)
+        {
+            Priority = BasePriority;
+        }
+        else
+        {
+            /* Calculate the new priority */
+            Priority = Thread->Priority + (BasePriority - CurrentBasePriority)-
+                       Thread->PriorityDecrement;
+
+            /* Make sure it won't enter RTP ranges */
+            if (Priority >= LOW_REALTIME_PRIORITY)
+                Priority = LOW_REALTIME_PRIORITY - 1;
+        }
+    }
+
+    /* Finally set the new base priority */
+    Thread->BasePriority = BasePriority;
+
+    /* Reset the decrements */
+    Thread->PriorityDecrement = 0;
+
+    /* If the priority will change, reset quantum and change it for real */
+    if (Priority != Thread->Priority)
+    {
+        Thread->Quantum = Thread->QuantumReset;
+        KiSetPriorityThread(Thread, Priority, &Released);
+    }
+
+    /* Release Lock if needed */
+    if (!Released)
+    {
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+    }
+    else
+    {
+        KeLowerIrql(OldIrql);
+    }
+
+    /* Return the Old Increment */
+    return CurrentIncrement;
+}
+
+/*
+ * @implemented
+ */
+KPRIORITY
+STDCALL
+KeSetPriorityThread(PKTHREAD Thread,
+                    KPRIORITY Priority)
+{
+    KPRIORITY OldPriority;
+    BOOLEAN Released = FALSE;
+    KIRQL OldIrql;
+
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Save the old Priority */
+    OldPriority = Thread->Priority;
+
+    /* Reset the Quantum and Decrements */
+    Thread->Quantum = Thread->QuantumReset;
+    Thread->PriorityDecrement = 0;
+
+    /* Set the new Priority */
+    KiSetPriorityThread(Thread, Priority, &Released);
+
+    /* Release Lock if needed */
+    if (!Released)
+    {
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+    }
+    else
+    {
         KeLowerIrql(OldIrql);
     }
+
+    /* Return Old Priority */
+    return OldPriority;
+}
+
+/*
+ * @implemented
+ *
+ * Sets thread's affinity
+ */
+NTSTATUS
+STDCALL
+KeSetAffinityThread(PKTHREAD Thread,
+                    KAFFINITY Affinity)
+{
+    KIRQL OldIrql;
+    LONG i;
+    PKPCR Pcr;
+    KAFFINITY ProcessorMask;
+
+    DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
+
+    /* Verify correct affinity */
+    if ((Affinity & Thread->ApcStatePointer[0]->Process->Affinity) !=
+        Affinity || !Affinity)
+    {
+        KEBUGCHECK(INVALID_AFFINITY_SET);
+    }
+
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    Thread->UserAffinity = Affinity;
+
+    if (Thread->SystemAffinityActive == FALSE) {
+
+        Thread->Affinity = Affinity;
+
+        if (Thread->State == Running) {
+
+            ProcessorMask = 1 << KeGetCurrentProcessorNumber();
+            if (Thread == KeGetCurrentThread()) {
+
+                if (!(Affinity & ProcessorMask)) {
+
+                    KiDispatchThreadNoLock(Ready);
+                    KeLowerIrql(OldIrql);
+                    return STATUS_SUCCESS;
+                }
+
+            } else {
+
+                for (i = 0; i < KeNumberProcessors; i++) {
+
+                    Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
+                    if (Pcr->Prcb->CurrentThread == Thread) {
+
+                        if (!(Affinity & ProcessorMask)) {
+
+                            KeReleaseDispatcherDatabaseLockFromDpcLevel();
+                            KiRequestReschedule(i);
+                            KeLowerIrql(OldIrql);
+                            return STATUS_SUCCESS;
+                        }
+
+                        break;
+                    }
+                }
+
+                ASSERT (i < KeNumberProcessors);
+            }
+        }
+    }
+
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return STATUS_SUCCESS;
 }
 
 /*
@@ -538,8 +1372,51 @@ VOID
 STDCALL
 KeTerminateThread(IN KPRIORITY Increment)
 {
-    /* Call our own internal routine */
-    PsTerminateCurrentThread(0);
+    KIRQL OldIrql;
+    PKTHREAD Thread = KeGetCurrentThread();
+
+    /* Lock the Dispatcher Database and the APC Queue */
+    DPRINT("Terminating\n");
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Remove the thread from the list */
+    RemoveEntryList(&Thread->ThreadListEntry);
+
+    /* Insert into the Reaper List */
+    DPRINT("List: %p\n", PspReaperList);
+    ((PETHREAD)Thread)->ReaperLink = PspReaperList;
+    PspReaperList = (PETHREAD)Thread;
+    DPRINT("List: %p\n", PspReaperList);
+
+    /* Check if it's active */
+    if (PspReaping == FALSE) {
+
+        /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
+        PspReaping = TRUE;
+        DPRINT("Terminating\n");
+        KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
+                      &PspReaperWorkItem.List,
+                      FALSE);
+    }
+
+    /* Handle Kernel Queues */
+    if (Thread->Queue) {
+
+        DPRINT("Waking Queue\n");
+        RemoveEntryList(&Thread->QueueListEntry);
+        KiWakeQueue(Thread->Queue);
+    }
+
+    /* Signal the thread */
+    Thread->DispatcherHeader.SignalState = TRUE;
+    if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) {
+
+        /* Satisfy waits */
+        KiWaitTest((PVOID)Thread, Increment);
+    }
+
+    /* Find a new Thread */
+    KiDispatchThreadNoLock(Terminated);
 }
 
 /*
@@ -553,27 +1430,27 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
     KIRQL OldIrql;
     PKTHREAD Thread = KeGetCurrentThread();
     BOOLEAN OldState;
-   
+
     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
-   
+
     /* Lock the Dispatcher Database and the APC Queue */
     OldIrql = KeAcquireDispatcherDatabaseLock();
     KiAcquireSpinLock(&Thread->ApcQueueLock);
-   
+
     /* Save the old State */
     OldState = Thread->Alerted[AlertMode];
-   
+
     /* If the Thread is Alerted, Clear it */
     if (OldState) {
-            
+
         Thread->Alerted[AlertMode] = FALSE;
-        
-    } else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
-        
+
+    } else if ((AlertMode != KernelMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
+
         /* If the mode is User and the Queue isn't empty, set Pending */
         Thread->ApcState.UserApcPending = TRUE;
     }
-   
+
     /* Release Locks and return the Old State */
     KiReleaseSpinLock(&Thread->ApcQueueLock);
     KeReleaseDispatcherDatabaseLock(OldIrql);
@@ -584,21 +1461,21 @@ VOID
 KiServiceCheck (VOID)
 {
     PKTHREAD Thread = KeGetCurrentThread();
-    
+
     /* Check if we need to inialize Win32 for this Thread */
     if (Thread->ServiceTable != KeServiceDescriptorTableShadow) {
-    
-        /* We do. Initialize it and save the new table */  
-        PsInitWin32Thread((PETHREAD)Thread);
+
+        /* We do. Initialize it and save the new table */
         Thread->ServiceTable = KeServiceDescriptorTableShadow;
+        PsInitWin32Thread((PETHREAD)Thread);
     }
 }
 
-/* 
+/*
  *
  * NOT EXPORTED
  */
-NTSTATUS 
+NTSTATUS
 STDCALL
 NtAlertResumeThread(IN  HANDLE ThreadHandle,
                     OUT PULONG SuspendCount)
@@ -610,20 +1487,18 @@ NtAlertResumeThread(IN  HANDLE ThreadHandle,
 
     /* Check if parameters are valid */
     if(PreviousMode != KernelMode) {
-     
+
         _SEH_TRY {
-            
-            ProbeForWrite(SuspendCount,
-                          sizeof(HANDLE),
-                          sizeof(ULONG));
-       
+
+            ProbeForWriteUlong(SuspendCount);
+
         } _SEH_HANDLE {
-            
+
             Status = _SEH_GetExceptionCode();
-            
+
         } _SEH_END;
     }
-   
+
     /* Reference the Object */
     Status = ObReferenceObjectByHandle(ThreadHandle,
                                        THREAD_SUSPEND_RESUME,
@@ -631,40 +1506,40 @@ NtAlertResumeThread(IN  HANDLE ThreadHandle,
                                        PreviousMode,
                                        (PVOID*)&Thread,
                                        NULL);
-   
-    /* Check for Success */ 
+
+    /* Check for Success */
     if (NT_SUCCESS(Status)) {
-   
+
         /* Call the Kernel Function */
         PreviousState = KeAlertResumeThread(&Thread->Tcb);
-   
+
         /* Dereference Object */
         ObDereferenceObject(Thread);
-        
+
         if (SuspendCount) {
-        
+
             _SEH_TRY {
-        
+
                 *SuspendCount = PreviousState;
-            
+
             } _SEH_HANDLE {
-            
+
                 Status = _SEH_GetExceptionCode();
-            
+
             } _SEH_END;
         }
     }
-    
+
     /* Return status */
     return Status;
 }
 
-/* 
+/*
  * @implemented
  *
  * EXPORTED
  */
-NTSTATUS 
+NTSTATUS
 STDCALL
 NtAlertThread (IN HANDLE ThreadHandle)
 {
@@ -679,27 +1554,27 @@ NtAlertThread (IN HANDLE ThreadHandle)
                                        PreviousMode,
                                        (PVOID*)&Thread,
                                        NULL);
-   
-    /* Check for Success */ 
+
+    /* Check for Success */
     if (NT_SUCCESS(Status)) {
-   
-        /* 
+
+        /*
          * Do an alert depending on the processor mode. If some kmode code wants to
          * enforce a umode alert it should call KeAlertThread() directly. If kmode
          * code wants to do a kmode alert it's sufficient to call it with Zw or just
-         * use KeAlertThread() directly 
+         * use KeAlertThread() directly
          */
         KeAlertThread(&Thread->Tcb, PreviousMode);
-   
+
         /* Dereference Object */
         ObDereferenceObject(Thread);
     }
-    
+
     /* Return status */
     return Status;
 }
 
-NTSTATUS 
+NTSTATUS
 STDCALL
 NtDelayExecution(IN BOOLEAN Alertable,
                  IN PLARGE_INTEGER DelayInterval)
@@ -707,31 +1582,35 @@ NtDelayExecution(IN BOOLEAN Alertable,
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     LARGE_INTEGER SafeInterval;
     NTSTATUS Status;
-   
+
     /* Check if parameters are valid */
     if(PreviousMode != KernelMode) {
-     
+
+        Status = STATUS_SUCCESS;
+        
         _SEH_TRY {
-            
-            ProbeForRead(DelayInterval,
-                         sizeof(LARGE_INTEGER),
-                         sizeof(ULONG));
-            
+
             /* make a copy on the kernel stack and let DelayInterval point to it so
                we don't need to wrap KeDelayExecutionThread in SEH! */
-            SafeInterval = *DelayInterval;
-       
+            SafeInterval = ProbeForReadLargeInteger(DelayInterval);
+            DelayInterval = &SafeInterval;
+
         } _SEH_HANDLE {
-            
+
             Status = _SEH_GetExceptionCode();
         } _SEH_END;
+        
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
    }
 
    /* Call the Kernel Function */
    Status = KeDelayExecutionThread(PreviousMode,
                                    Alertable,
-                                   &SafeInterval);
-   
+                                   DelayInterval);
+
    /* Return Status */
    return Status;
 }