KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / kthread.c
index 561c685..709f45d 100644 (file)
 /*
- *  ReactOS kernel
- *  Copyright (C) 2000  ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: kthread.c,v 1.40 2003/07/10 17:44:06 royce Exp $
- *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/kthread.c
  * PURPOSE:         Microkernel thread support
- * PROGRAMMER:      David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * 
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  David Welch (welch@cwcom.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/ps.h>
-#include <internal/id.h>
-#include <internal/pool.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #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;
+extern PETHREAD PspReaperList;
+
 /* FUNCTIONS *****************************************************************/
 
+STATIC 
 VOID
-KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, 
-               PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry, BOOLEAN Dirty)
+KiRequestReschedule(CCHAR Processor)
 {
-  assert(SwapEntry == 0);
-  if (PhysAddr.QuadPart  != 0)
-    {
-      MmReleasePageMemoryConsumer(MC_NPPOOL, PhysAddr);
+    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(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);
 }
 
-NTSTATUS 
-KeReleaseThread(PETHREAD Thread)
+STATIC
+VOID 
+KiRemoveFromThreadList(PKTHREAD Thread)
+{
+    ASSERT(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 != Ready) {
+                
+                DPRINT1("%d/%d\n", &current, current->State);
+            }
+            
+            ASSERT(current->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 == 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);
+}
+
+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;
+        do {
+            RemoveEntryList (&WaitBlock->WaitListEntry);
+            WaitBlock = WaitBlock->NextWaitBlock;
+        } while (WaitBlock != Thread->WaitBlockList);
+        Thread->WaitBlockList = NULL;
+        
+        /* Dispatch it and return status */
+        KiDispatchThreadNoLock (Ready);
+        if (Status != NULL) *Status = STATUS_KERNEL_APC;
+
+    } else {
+
+        /* Set the Thread Data as Requested */
+        DPRINT("Dispatching Thread as blocked: %d\n", Thread->WaitStatus);
+        Thread->Alertable = Alertable;
+        Thread->WaitMode = (UCHAR)WaitMode;
+        Thread->WaitReason = WaitReason;
+        
+        /* Dispatch it and return status */
+        KiDispatchThreadNoLock(Waiting);
+        DPRINT("Dispatching Thread as blocked: %d\n", Thread->WaitStatus);
+        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 (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 {
+        
+        ULONG 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;
+            }
+            
+        } else {
+            
+            Thread->Quantum = Thread->ApcState.Process->ThreadQuantum;
+        }
+     
+        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)) {
+            
+            ULONG 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
+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
 /*
- * FUNCTION: Releases the resource allocated for a thread by
- * KeInitializeThread
- * NOTE: The thread had better not be running when this is called
+ * @implemented
  */
+PKTHREAD 
+STDCALL 
+KeGetCurrentThread(VOID)
 {
-  extern unsigned int init_stack;
+#ifdef CONFIG_SMP
+    ULONG Flags;
+    PKTHREAD Thread;
+    Ke386SaveFlags(Flags);
+    Ke386DisableInterrupts();
+    Thread = KeGetCurrentPrcb()->CurrentThread;
+    Ke386RestoreFlags(Flags);
+    return Thread;
+#else
+    return(KeGetCurrentPrcb()->CurrentThread);
+#endif
+}
 
-  if (Thread->Tcb.StackLimit != (ULONG)&init_stack)
-    {       
-      MmLockAddressSpace(MmGetKernelAddressSpace());
-      MmFreeMemoryArea(MmGetKernelAddressSpace(),
-                      (PVOID)Thread->Tcb.StackLimit,
-                      MM_STACK_SIZE,
-                      KeFreeStackPage,
-                      NULL);
-      MmUnlockAddressSpace(MmGetKernelAddressSpace());
-    }
-  Thread->Tcb.StackLimit = 0;
-  Thread->Tcb.InitialStack = NULL;
-  Thread->Tcb.StackBase = NULL;
-  Thread->Tcb.KernelStack = NULL;
-  return(STATUS_SUCCESS);
+VOID
+STDCALL
+KeSetPreviousMode(ULONG Mode)
+{
+    PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
+}
+
+/*
+ * @implemented
+ */
+KPROCESSOR_MODE 
+STDCALL
+KeGetPreviousMode(VOID)
+{
+    return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
 }
 
 VOID
-KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
+STDCALL
+KeRundownThread(VOID)
+{
+    KIRQL OldIrql;
+    PKTHREAD Thread = KeGetCurrentThread();
+    PLIST_ENTRY CurrentEntry;
+    PKMUTANT Mutant;
+    
+    DPRINT("KeRundownThread: %x\n", Thread);
+
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    while (!IsListEmpty(&Thread->MutantListHead)) {
+    
+        /* Get the Mutant */
+       CurrentEntry = RemoveHeadList(&Thread->MutantListHead);
+        Mutant = CONTAINING_RECORD(CurrentEntry, KMUTANT, MutantListEntry);
+        ASSERT(Mutant->ApcDisable == 0);
+    
+        /* Uncondtionally abandon it */
+        DPRINT("Abandonning the Mutant\n");
+        Mutant->Header.SignalState = 1;
+        Mutant->Abandoned = TRUE;
+        Mutant->OwnerThread = NULL;
+        RemoveEntryList(&Mutant->MutantListEntry);
+        
+        /* 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);
+        }
+    }
+   
+    /* 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;
+}
+
+BOOLEAN
+STDCALL
+KiInsertQueueApc(PKAPC Apc,
+                 KPRIORITY PriorityBoost);
+
 /*
- * FUNCTION: Initialize the microkernel state of the thread
+ * Used by the debugging code to freeze all the process's threads
+ * while the debugger is examining their state.
  */
+VOID
+STDCALL
+KeFreezeAllThreads(PKPROCESS Process)
 {
-  PVOID KernelStack;
-  NTSTATUS Status;
-  extern unsigned int init_stack_top;
-  extern unsigned int init_stack;
-  PMEMORY_AREA StackArea;
-  ULONG i;
-  
-  KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
-                              InternalThreadType,
-                              sizeof(ETHREAD),
-                              FALSE);
-  InitializeListHead(&Thread->MutantListHead);
-  if (!First)
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PKTHREAD Current;
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+
+    /* Acquire Lock */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Loop the Process's Threads */
+    CurrentEntry = Process->ThreadListHead.Flink;
+    while (CurrentEntry != &Process->ThreadListHead)
     {
-      KernelStack = NULL;
-      
-      MmLockAddressSpace(MmGetKernelAddressSpace());
-      Status = MmCreateMemoryArea(NULL,
-                                 MmGetKernelAddressSpace(),
-                                 MEMORY_AREA_KERNEL_STACK,
-                                 &KernelStack,
-                                 MM_STACK_SIZE,
-                                 0,
-                                 &StackArea,
-                                 FALSE,
-                                 FALSE);
-      MmUnlockAddressSpace(MmGetKernelAddressSpace());
+        /* Get the Thread */
+        Current = CONTAINING_RECORD(CurrentEntry, KTHREAD, ThreadListEntry);
+        
+        /* Make sure it's not ours */
+        if (Current == CurrentThread) continue;
+        
+        /* Make sure it wasn't already frozen, and that it's not suspended */
+        if (!(++Current->FreezeCount) && !(Current->SuspendCount))
+        {
+            /* Insert the APC */
+            if (!KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT)) 
+            {
+                /* Unsignal the Semaphore, the APC already got inserted */
+                Current->SuspendSemaphore.Header.SignalState--;
+            }
+        }
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    /* 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;
+    
+    /* Increment it */
+    Thread->SuspendCount++;
+    
+    /* Check if we should suspend it */
+    if (!PreviousCount && !Thread->FreezeCount) {
+    
+        /* Insert the APC */
+        if (!KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT)) {
+            
+            /* 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)
+{
+    ULONG PreviousCount;
+    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 == 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;    
+    
+    /* 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);
+        }
+    }
+
+    /* Release Locks and return the Old State */
+    KiReleaseSpinLock(&Thread->ApcQueueLock);
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return PreviousCount;
+}
+
+BOOLEAN
+STDCALL
+KeAlertThread(PKTHREAD Thread, 
+              KPROCESSOR_MODE AlertMode)
+{
+    KIRQL OldIrql;
+    BOOLEAN PreviousState;
+
+    /* Acquire the Dispatcher Database Lock */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+   
+    /* Save the Previous State */
+    PreviousState = Thread->Alerted[AlertMode];
       
-      if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("Failed to create thread stack\n");
-         KeBugCheck(0);
-       }
-      for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
-       {
-         PHYSICAL_ADDRESS Page;
-         Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
-         if (!NT_SUCCESS(Status))
-           {
-             KeBugCheck(0);
-           }
-         Status = MmCreateVirtualMapping(NULL,
-                                         KernelStack + (i * PAGE_SIZE),
-                                         PAGE_EXECUTE_READWRITE,
-                                         Page,
-                                         TRUE);
-       }
-      Thread->InitialStack = KernelStack + MM_STACK_SIZE;
-      Thread->StackBase = KernelStack + MM_STACK_SIZE;
-      Thread->StackLimit = (ULONG)KernelStack;
-      Thread->KernelStack = KernelStack + MM_STACK_SIZE;
-    }
-  else
-    {
-      Thread->InitialStack = (PVOID)&init_stack_top;
-      Thread->StackBase = (PVOID)&init_stack_top;
-      Thread->StackLimit = (ULONG)&init_stack;
-      Thread->KernelStack = (PVOID)&init_stack_top;
-    }
-  
-  /* 
-   * The Native API function will initialize the TEB field later 
-   */
-  Thread->Teb = NULL;
-  Thread->TlsArray = NULL;
-  Thread->DebugActive = 0;
-  Thread->State = THREAD_STATE_INITIALIZED;
-  Thread->Alerted[0] = 0;
-  Thread->Alerted[1] = 0;
-  Thread->Iopl = 0;
-  /*
-   * FIXME: Think how this might work
-   */
-  Thread->NpxState = 0;
-  
-  Thread->Saturation = 0;
-  Thread->Priority = 0; 
-  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->ContextSwitches = 0;
-  Thread->WaitStatus = STATUS_SUCCESS;
-  Thread->WaitIrql = 0;
-  Thread->WaitMode = 0;
-  Thread->WaitNext = 0;
-  Thread->WaitBlockList = NULL;
-  Thread->WaitListEntry.Flink = NULL;
-  Thread->WaitListEntry.Blink = NULL;
-  Thread->WaitTime = 0;
-  Thread->BasePriority = 0; 
-  Thread->DecrementCount = 0;
-  Thread->PriorityDecrement = 0;
-  Thread->Quantum = 0;
-  memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4);
-  Thread->LegoData = 0;
-  /*
-   * FIXME: Why this?
-   */
-  Thread->KernelApcDisable = 1;
-  Thread->UserAffinity = Process->Affinity;
-  Thread->SystemAffinityActive = 0;
-  Thread->PowerState = 0;
-  Thread->NpxIrql = 0;
-  Thread->ServiceTable = KeServiceDescriptorTable;
-  Thread->Queue = NULL;
-  KeInitializeSpinLock(&Thread->ApcQueueLock);
-  memset(&Thread->Timer, 0, sizeof(KTIMER));
-  Thread->QueueListEntry.Flink = NULL;
-  Thread->QueueListEntry.Blink = NULL;
-  Thread->Affinity = Process->Affinity;
-  Thread->Preempted = 0;
-  Thread->ProcessReadyQueue = 0;
-  Thread->KernelStackResident = 1;
-  Thread->NextProcessor = 0;
-  Thread->CallbackStack = NULL;
-  Thread->Win32Thread = 0;
-  Thread->TrapFrame = NULL;
-  Thread->ApcStatePointer[0] = NULL;
-  Thread->ApcStatePointer[1] = NULL;
-  Thread->EnableStackSwap = 0;
-  Thread->LargeStack = 0;
-  Thread->ResourceIndex = 0;
-  Thread->PreviousMode = KernelMode;
-  Thread->KernelTime = 0;
-  Thread->UserTime = 0;
-  memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE));
-  Thread->Alertable = 1;
-  Thread->ApcStateIndex = 0;
-  Thread->ApcQueueable = 0;
-  Thread->AutoAlignment = 0;
-  KeInitializeApc(&Thread->SuspendApc,
-                 Thread,
-                 OriginalApcEnvironment,
-                 PiSuspendThreadKernelRoutine,
-                 PiSuspendThreadRundownRoutine,
-                 PiSuspendThreadNormalRoutine,
-                 KernelMode,
-                 NULL);
-  KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
-  Thread->ThreadListEntry.Flink = NULL;
-  Thread->ThreadListEntry.Blink = NULL;
-  Thread->FreezeCount = 0;
-  Thread->SuspendCount = 0;
-  
-  /*
-   * Initialize ReactOS specific members
-   */
-  Thread->ProcessThreadListEntry.Flink = NULL;
-  Thread->ProcessThreadListEntry.Blink = NULL;
-   
-   /*
-    * Do x86 specific part
-    */
+    /* Return if Thread is already alerted. */
+    if (PreviousState == FALSE) {
+       
+        /* If it's Blocked, unblock if it we should */
+        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;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+STDCALL
+KeCapturePersistentThreadState(IN PVOID CurrentThread,
+                               IN ULONG Setting1,
+                               IN ULONG Setting2,
+                               IN ULONG Setting3,
+                               IN ULONG Setting4,
+                               IN ULONG Setting5,
+                               IN PVOID ThreadState)
+{
+    UNIMPLEMENTED;
+}
+
+/*
+ * FUNCTION: Initialize the microkernel state of the thread
+ */
+VOID
+STDCALL
+KeInitializeThread(PKPROCESS Process, 
+                   PKTHREAD Thread, 
+                   PKSYSTEM_ROUTINE SystemRoutine,
+                   PKSTART_ROUTINE StartRoutine,
+                   PVOID StartContext,
+                   PCONTEXT Context,
+                   PVOID Teb,
+                   PVOID KernelStack)
+{  
+    /* Initalize the Dispatcher Header */
+    DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread, Process);
+    KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
+                                 ThreadObject,
+                                 sizeof(KTHREAD),
+                                 FALSE);
+    
+    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);
+       
+    /* Initialize the Mutant List */
+    InitializeListHead(&Thread->MutantListHead);
+    
+    /* Setup the Service Descriptor Table for Native Calls */
+    Thread->ServiceTable = KeServiceDescriptorTable;
+    
+    /* Setup APC Fields */
+    InitializeListHead(&Thread->ApcState.ApcListHead[0]);
+    InitializeListHead(&Thread->ApcState.ApcListHead[1]);
+    Thread->ApcState.Process = Process;
+    Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
+    Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
+    Thread->ApcStateIndex = OriginalApcEnvironment;
+    KeInitializeSpinLock(&Thread->ApcQueueLock);
+    
+    /* 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);
+             
+    /* 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->Quantum = Process->ThreadQuantum;
+    Thread->Affinity = Process->Affinity;
+    Thread->Priority = Process->BasePriority;
+    Thread->UserAffinity = Process->Affinity;
+    Thread->DisableBoost = Process->DisableBoost;
+    Thread->AutoAlignment = Process->AutoAlignment;
+    Thread->Iopl = Process->Iopl;
+    
+    /* 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);
+    DPRINT("Thread initalized\n");
+}
+
+
+/*
+ * @implemented
+ */
+KPRIORITY
+STDCALL
+KeQueryPriorityThread (IN PKTHREAD Thread)
+{
+    return Thread->Priority;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+STDCALL
+KeQueryRuntimeThread(IN PKTHREAD Thread,
+                     OUT PULONG UserTime)
+{
+    /* Return the User Time */
+    *UserTime = Thread->UserTime;
+    
+    /* Return the Kernel Time */
+    return Thread->KernelTime;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+STDCALL
+KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
+{
+    PKTHREAD Thread = KeGetCurrentThread();
+    BOOLEAN PreviousState;
+    KIRQL OldIrql;
+     /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Save Old State */
+    PreviousState = Thread->EnableStackSwap;
+
+    /* Set New State */
+    Thread->EnableStackSwap = Enable;
+
+    /* No, Release Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+        
+    /* Return Old State */
+    return PreviousState;
+}
+
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+KeRevertToUserAffinityThread(VOID)
+{
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+    KIRQL OldIrql;
+
+    ASSERT(CurrentThread->SystemAffinityActive != FALSE);
+        
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Return to User Affinity */
+    CurrentThread->Affinity = CurrentThread->UserAffinity;
+
+    /* 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;
+        KiDispatchThreadNoLock(Ready);
+        KeLowerIrql(OldIrql);
+    }
+}
+
+/*
+ * @implemented
+ */
+CCHAR
+STDCALL
+KeSetIdealProcessorThread(IN PKTHREAD Thread,
+                          IN CCHAR Processor)
+{
+    CCHAR PreviousIdealProcessor;
+    KIRQL OldIrql;
+    
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Save Old Ideal Processor */
+    PreviousIdealProcessor = Thread->IdealProcessor;
+
+    /* Set New Ideal Processor */
+    Thread->IdealProcessor = Processor;
+    
+    /* Release Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);   
+    
+    /* Return Old Ideal Processor */
+    return PreviousIdealProcessor;
+}
+
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+KeSetSystemAffinityThread(IN KAFFINITY Affinity)
+{
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+    KIRQL OldIrql;
+
+    ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
+        
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Set the System Affinity Specified */
+    CurrentThread->Affinity = 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;
+        KiDispatchThreadNoLock(Ready);
+        KeLowerIrql(OldIrql);
+    }
 }
 
 /*
  * @implemented
  */
-VOID STDCALL
-KeRescheduleThread()
+LONG STDCALL
+KeSetBasePriorityThread (PKTHREAD      Thread,
+                        LONG           Increment)
+/*
+ * Sets thread's base priority relative to the process' base priority
+ * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
+ */
 {
-  PsDispatchThread(THREAD_STATE_READY);
+   KPRIORITY Priority;
+   if (Increment < -2)
+     {
+       Increment = -2;
+     }
+   else if (Increment > 2)
+     {
+       Increment = 2;
+     }
+   Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
+   if (Priority < LOW_PRIORITY)
+   {
+     Priority = LOW_PRIORITY;
+   }
+   else if (Priority >= MAXIMUM_PRIORITY)
+     {
+       Thread->BasePriority = HIGH_PRIORITY;
+     }
+   KeSetPriorityThread(Thread, Priority);
+   return 1;
+}
+
+/*
+ * @implemented
+ */
+KPRIORITY 
+STDCALL
+KeSetPriorityThread(PKTHREAD Thread, 
+                    KPRIORITY Priority)
+{
+    KPRIORITY OldPriority;
+    KIRQL OldIrql;
+    PKTHREAD CurrentThread;
+    ULONG Mask;
+    int i;
+    PKPCR Pcr;
+
+    if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY) {
+        
+        KEBUGCHECK(0);
+    }
+
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    OldPriority = Thread->Priority;
+
+    if (OldPriority != Priority) {
+        
+        CurrentThread = KeGetCurrentThread();
+        
+        if (Thread->State == Ready) {
+            
+            KiRemoveFromThreadList(Thread);
+            Thread->BasePriority = Thread->Priority = (CHAR)Priority;
+            KiInsertIntoThreadList(Priority, Thread);
+            
+            if (CurrentThread->Priority < Priority) {
+                
+                KiDispatchThreadNoLock(Ready);
+                KeLowerIrql(OldIrql);
+                return (OldPriority);
+            }
+        
+        } else if (Thread->State == Running)  {
+            
+            Thread->BasePriority = Thread->Priority = (CHAR)Priority;
+            
+            if (Priority < OldPriority) {
+                
+                /* Check for threads with a higher priority */
+                Mask = ~((1 << (Priority + 1)) - 1);
+                if (PriorityListMask & Mask) {
+                    
+                    if (Thread == CurrentThread) {
+                        
+                        KiDispatchThreadNoLock(Ready);
+                        KeLowerIrql(OldIrql);
+                        return (OldPriority);
+                        
+                    } else {
+                        
+                        for (i = 0; i < KeNumberProcessors; i++) {
+                            
+                            Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
+                            
+                            if (Pcr->Prcb->CurrentThread == Thread) {
+
+                                KeReleaseDispatcherDatabaseLockFromDpcLevel();
+                                KiRequestReschedule(i);
+                                KeLowerIrql(OldIrql);
+                                return (OldPriority);
+                            }
+                        }
+                    }
+                }
+            }
+        }  else  {
+            
+            Thread->BasePriority = Thread->Priority = (CHAR)Priority;
+        }
+    }
+    
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return(OldPriority);
+}
+
+/*
+ * @implemented
+ *
+ * Sets thread's affinity
+ */
+NTSTATUS 
+STDCALL
+KeSetAffinityThread(PKTHREAD Thread,
+                    KAFFINITY Affinity)
+{
+    KIRQL OldIrql;
+    ULONG i;
+    PKPCR Pcr;
+    KAFFINITY ProcessorMask;
+
+    DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
+
+    ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
+
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    Thread->UserAffinity = Affinity;
+    
+    if (Thread->SystemAffinityActive == FALSE) {
+        
+        Thread->Affinity = Affinity;
+        
+        if (Thread->State == Running) {
+            
+            ProcessorMask = 1 << KeGetCurrentKPCR()->ProcessorNumber;
+            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;
+}
+
+/*
+ * @implemented
+ */
+ /* The Increment Argument seems to be ignored by NT and always 0 when called */
+VOID
+STDCALL
+KeTerminateThread(IN KPRIORITY Increment)
+{
+    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);
+}
+
+/*
+ * FUNCTION: Tests whether there are any pending APCs for the current thread
+ * and if so the APCs will be delivered on exit from kernel mode
+ */
+BOOLEAN
+STDCALL
+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]))) {
+        
+        /* 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);
+    return OldState;
+}
+
+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);
+        Thread->ServiceTable = KeServiceDescriptorTableShadow;
+    }
+}
+
+/* 
+ *
+ * NOT EXPORTED
+ */
+NTSTATUS 
+STDCALL
+NtAlertResumeThread(IN  HANDLE ThreadHandle,
+                    OUT PULONG SuspendCount)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PETHREAD Thread;
+    NTSTATUS Status;
+    ULONG PreviousState;
+
+    /* Check if parameters are valid */
+    if(PreviousMode != KernelMode) {
+     
+        _SEH_TRY {
+            
+            ProbeForWrite(SuspendCount,
+                          sizeof(HANDLE),
+                          sizeof(ULONG));
+       
+        } _SEH_HANDLE {
+            
+            Status = _SEH_GetExceptionCode();
+            
+        } _SEH_END;
+    }
+   
+    /* Reference the Object */
+    Status = ObReferenceObjectByHandle(ThreadHandle,
+                                       THREAD_SUSPEND_RESUME,
+                                       PsThreadType,
+                                       PreviousMode,
+                                       (PVOID*)&Thread,
+                                       NULL);
+   
+    /* 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 
+STDCALL
+NtAlertThread (IN HANDLE ThreadHandle)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PETHREAD Thread;
+    NTSTATUS Status;
+
+    /* Reference the Object */
+    Status = ObReferenceObjectByHandle(ThreadHandle,
+                                       THREAD_SUSPEND_RESUME,
+                                       PsThreadType,
+                                       PreviousMode,
+                                       (PVOID*)&Thread,
+                                       NULL);
+   
+    /* 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 
+         */
+        KeAlertThread(&Thread->Tcb, PreviousMode);
+   
+        /* Dereference Object */
+        ObDereferenceObject(Thread);
+    }
+    
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS 
+STDCALL
+NtDelayExecution(IN BOOLEAN Alertable,
+                 IN PLARGE_INTEGER DelayInterval)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    LARGE_INTEGER SafeInterval;
+    NTSTATUS Status;
+   
+    /* Check if parameters are valid */
+    if(PreviousMode != KernelMode) {
+     
+        _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;
+       
+        } _SEH_HANDLE {
+            
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
+   }
+
+   /* Call the Kernel Function */
+   Status = KeDelayExecutionThread(PreviousMode,
+                                   Alertable,
+                                   &SafeInterval);
+   
+   /* Return Status */
+   return Status;
 }