[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / ps / thread.c
index 45fd5b2..d05fc85 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ps/thread.c
- * PURPOSE:         Thread managment
- *
- * PROGRAMMERS:     David Welch (welch@mcmail.com)
- *                  Phillip Susi
+ * PURPOSE:         Process Manager: Thread Management
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Thomas Weidenmueller (w3seek@reactos.org)
  */
 
 /* INCLUDES ****************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* GLOBALS ******************************************************************/
 
-extern LIST_ENTRY PsActiveProcessHead;
-extern PEPROCESS PsIdleProcess;
-extern PVOID PspSystemDllEntryPoint;
-extern PHANDLE_TABLE PspCidTable;
+extern BOOLEAN CcPfEnablePrefetcher;
+extern ULONG MmReadClusterSize;
+POBJECT_TYPE PsThreadType = NULL;
 
-POBJECT_TYPE EXPORTED PsThreadType = NULL;
-
-/* FUNCTIONS ***************************************************************/
+/* PRIVATE FUNCTIONS *********************************************************/
 
 VOID
-STDCALL
-PspThreadSpecialApc(PKAPC Apc,
-                    PKNORMAL_ROUTINE* NormalRoutine,
-                    PVOID* NormalContext,
-                    PVOID* SystemArgument1,
-                    PVOID* SystemArgument2)
+NTAPI
+PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
+                     IN PVOID StartContext)
 {
-    ExFreePool(Apc);
-}
+    PETHREAD Thread;
+    PTEB Teb;
+    BOOLEAN DeadThread = FALSE;
+    KIRQL OldIrql;
+    PAGED_CODE();
+    PSTRACE(PS_THREAD_DEBUG,
+            "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
 
-VOID
-STDCALL
-PspUserThreadStartup(PKSTART_ROUTINE StartRoutine,
-                     PVOID StartContext)
-{
-    PKAPC ThreadApc;
-    PETHREAD Thread = PsGetCurrentThread();
+    /* Go to Passive Level */
+    KeLowerIrql(PASSIVE_LEVEL);
+    Thread = PsGetCurrentThread();
+
+    /* Check if the thread is dead */
+    if (Thread->DeadThread)
+    {
+        /* Remember that we're dead */
+        DeadThread = TRUE;
+    }
+    else
+    {
+        /* Get the Locale ID and save Preferred Proc */
+        Teb =  NtCurrentTeb();
+        Teb->CurrentLocale = MmGetSessionLocaleId();
+        Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
+    }
+
+    /* Check if this is a dead thread, or if we're hiding */
+    if (!(Thread->DeadThread) && !(Thread->HideFromDebugger))
+    {
+        /* We're not, so notify the debugger */
+        DbgkCreateThread(Thread, StartContext);
+    }
 
-    DPRINT("I am a new USER thread. This is my start routine: %p. This my context: %p."
-           "This is my IRQL: %d. This is my Thread Pointer: %x.\n", StartRoutine,
-            StartContext, KeGetCurrentIrql(), Thread);
+    /* Make sure we're not already dead */
+    if (!DeadThread)
+    {
+        /* Check if the Prefetcher is enabled */
+        if (CcPfEnablePrefetcher)
+        {
+            /* FIXME: Prepare to prefetch this process */
+        }
 
-    if (!Thread->Terminated) {
+        /* Raise to APC */
+        KeRaiseIrql(APC_LEVEL, &OldIrql);
 
-        /* Allocate the APC */
-        ThreadApc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('T', 'h', 'r','d'));
+        /* Queue the User APC */
+        KiInitializeUserApc(KeGetExceptionFrame(&Thread->Tcb),
+                            KeGetTrapFrame(&Thread->Tcb),
+                            PspSystemDllEntryPoint,
+                            NULL,
+                            PspSystemDllBase,
+                            NULL);
 
-        /* Initialize it */
-        KeInitializeApc(ThreadApc,
-                        &Thread->Tcb,
-                        OriginalApcEnvironment,
-                        PspThreadSpecialApc,
-                        NULL,
-                        PspSystemDllEntryPoint,
-                        UserMode,
-                        NULL);
+        /* Lower it back to passive */
+        KeLowerIrql(PASSIVE_LEVEL);
+    }
+    else
+    {
+        /* We're dead, kill us now */
+        PspTerminateThreadByPointer(Thread,
+                                    STATUS_THREAD_IS_TERMINATING,
+                                    TRUE);
+    }
 
-        /* Insert it into the queue */
-        KeInsertQueueApc(ThreadApc, NULL, NULL, IO_NO_INCREMENT);
-        Thread->Tcb.ApcState.UserApcPending = TRUE;
+    /* Do we have a cookie set yet? */
+    if (!SharedUserData->Cookie)
+    {
+        LARGE_INTEGER SystemTime;
+        ULONG NewCookie;
+        PKPRCB Prcb;
+
+        /* Generate a new cookie */
+        KeQuerySystemTime(&SystemTime);
+        Prcb = KeGetCurrentPrcb();
+        NewCookie = Prcb->MmPageFaultCount ^ Prcb->InterruptTime ^
+                    SystemTime.u.LowPart ^ SystemTime.u.HighPart ^
+                    (ULONG_PTR)&SystemTime;
+
+        /* Set the new cookie*/
+        InterlockedCompareExchange((LONG*)&SharedUserData->Cookie,
+                                   NewCookie,
+                                   0);
     }
+}
 
-    /* Go to Passive Level and notify debugger */
-    KeLowerIrql(PASSIVE_LEVEL);
-    DbgkCreateThread(StartContext);
+LONG
+PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers)
+{
+    /* Print debugging information */
+    DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
+            ExceptionPointers);
+    DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
+            ExceptionPointers->ExceptionRecord->ExceptionCode,
+            ExceptionPointers->ExceptionRecord->ExceptionAddress,
+            ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
+            ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
+            ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
+            ExceptionPointers->ExceptionRecord->ExceptionInformation[3]);
+
+    /* Bugcheck the system */
+    KeBugCheckEx(SYSTEM_THREAD_EXCEPTION_NOT_HANDLED,
+                 ExceptionPointers->ExceptionRecord->ExceptionCode,
+                 (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
+                 (ULONG_PTR)ExceptionPointers->ExceptionRecord,
+                 (ULONG_PTR)ExceptionPointers->ContextRecord);
+    return 0;
 }
 
 VOID
-STDCALL
-PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine,
-                       PVOID StartContext)
+NTAPI
+PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
+                       IN PVOID StartContext)
 {
-    PETHREAD Thread = PsGetCurrentThread();
+    PETHREAD Thread;
+    PSTRACE(PS_THREAD_DEBUG,
+            "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
 
     /* Unlock the dispatcher Database */
     KeLowerIrql(PASSIVE_LEVEL);
+    Thread = PsGetCurrentThread();
 
-    /* Make sure it's not terminated by now */
-    if (!Thread->Terminated) {
-
-        /* Call it */
-        (StartRoutine)(StartContext);
+    /* Make sure the thread isn't gone */
+    _SEH2_TRY
+    {
+        if (!(Thread->Terminated) && !(Thread->DeadThread))
+        {
+            /* Call the Start Routine */
+            StartRoutine(StartContext);
+        }
     }
+    _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation()))
+    {
+        /* Bugcheck if we got here */
+        KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
+    }
+    _SEH2_END;
 
     /* Exit the thread */
-    PspExitThread(STATUS_SUCCESS);
+    PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 PspCreateThread(OUT PHANDLE ThreadHandle,
                 IN ACCESS_MASK DesiredAccess,
-                IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
+                IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
                 IN HANDLE ProcessHandle,
                 IN PEPROCESS TargetProcess,
                 OUT PCLIENT_ID ClientId,
@@ -111,150 +184,196 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
     HANDLE hThread;
     PEPROCESS Process;
     PETHREAD Thread;
-    PTEB TebBase;
-    KIRQL OldIrql;
+    PTEB TebBase = NULL;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    NTSTATUS Status;
+    NTSTATUS Status, AccessStatus;
     HANDLE_TABLE_ENTRY CidEntry;
-    PVOID KernelStack;
+    ACCESS_STATE LocalAccessState;
+    PACCESS_STATE AccessState = &LocalAccessState;
+    AUX_ACCESS_DATA AuxData;
+    BOOLEAN Result, SdAllocated;
+    PSECURITY_DESCRIPTOR SecurityDescriptor;
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    PAGED_CODE();
+    PSTRACE(PS_THREAD_DEBUG,
+            "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
+            ThreadContext, TargetProcess, ProcessHandle);
 
-    /* Reference the Process by handle or pointer, depending on what we got */
-    DPRINT("PspCreateThread: %x, %x, %x\n", ProcessHandle, TargetProcess, ThreadContext);
-    if (ProcessHandle) {
+    /* If we were called from PsCreateSystemThread, then we're kernel mode */
+    if (StartRoutine) PreviousMode = KernelMode;
 
+    /* Reference the Process by handle or pointer, depending on what we got */
+    if (ProcessHandle)
+    {
         /* Normal thread or System Thread */
-        DPRINT("Referencing Parent Process\n");
         Status = ObReferenceObjectByHandle(ProcessHandle,
                                            PROCESS_CREATE_THREAD,
                                            PsProcessType,
                                            PreviousMode,
                                            (PVOID*)&Process,
                                            NULL);
-    } else {
-
+        PSREFTRACE(Process);
+    }
+    else
+    {
         /* System thread inside System Process, or Normal Thread with a bug */
-        if (StartRoutine) {
-
+        if (StartRoutine)
+        {
             /* Reference the Process by Pointer */
-            DPRINT("Referencing Parent System Process\n");
             ObReferenceObject(TargetProcess);
             Process = TargetProcess;
             Status = STATUS_SUCCESS;
-
-        } else {
-
+        }
+        else
+        {
             /* Fake ObReference returning this */
             Status = STATUS_INVALID_HANDLE;
         }
     }
 
     /* Check for success */
-    if(!NT_SUCCESS(Status)) {
+    if (!NT_SUCCESS(Status)) return Status;
 
-        DPRINT1("Invalid Process Handle, or no handle given\n");
-        return(Status);
+    /* Also make sure that User-Mode isn't trying to create a system thread */
+    if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
+    {
+        /* Fail */
+        ObDereferenceObject(Process);
+        return STATUS_INVALID_HANDLE;
     }
 
     /* Create Thread Object */
-    DPRINT("Creating Thread Object\n");
     Status = ObCreateObject(PreviousMode,
                             PsThreadType,
                             ObjectAttributes,
-                            KernelMode,
+                            PreviousMode,
                             NULL,
                             sizeof(ETHREAD),
                             0,
                             0,
                             (PVOID*)&Thread);
-
-    /* Check for success */
-    if (!NT_SUCCESS(Status)) {
-
-        /* Dereference the Process */
-        DPRINT1("Failed to Create Thread Object\n");
+    if (!NT_SUCCESS(Status))
+    {
+        /* We failed; dereference the process and exit */
         ObDereferenceObject(Process);
-        return(Status);
+        return Status;
     }
 
     /* Zero the Object entirely */
-    DPRINT("Cleaning Thread Object\n");
     RtlZeroMemory(Thread, sizeof(ETHREAD));
 
+    /* Initialize rundown protection */
+    ExInitializeRundownProtection(&Thread->RundownProtect);
+
+    /* Initialize exit code */
+    Thread->ExitStatus = STATUS_PENDING;
+
+    /* Set the Process CID */
+    Thread->ThreadsProcess = Process;
+    Thread->Cid.UniqueProcess = Process->UniqueProcessId;
+
     /* Create Cid Handle */
-    DPRINT("Creating Thread Handle (CID)\n");
-    CidEntry.u1.Object = Thread;
-    CidEntry.u2.GrantedAccess = 0;
+    CidEntry.Object = Thread;
+    CidEntry.GrantedAccess = 0;
     Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
-    if (!Thread->Cid.UniqueThread) {
-
-        DPRINT1("Failed to create Thread Handle (CID)\n");
-        ObDereferenceObject(Process);
+    if (!Thread->Cid.UniqueThread)
+    {
+        /* We couldn't create the CID, dereference the thread and fail */
         ObDereferenceObject(Thread);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    /* Initialize Lists */
-    DPRINT("Initialliazing Thread Lists and Locks\n");
+    /* Save the read cluster size */
+    Thread->ReadClusterSize = MmReadClusterSize;
+
+    /* Initialize the LPC Reply Semaphore */
+    KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
+
+    /* Initialize the list heads and locks */
     InitializeListHead(&Thread->LpcReplyChain);
     InitializeListHead(&Thread->IrpList);
+    InitializeListHead(&Thread->PostBlockList);
     InitializeListHead(&Thread->ActiveTimerListHead);
     KeInitializeSpinLock(&Thread->ActiveTimerListLock);
 
-    /* Initialize LPC */
-    DPRINT("Initialliazing Thread Semaphore\n");
-    KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, MAXLONG);
-
-    /* Allocate Stack for non-GUI Thread */
-    DPRINT("Initialliazing Thread Stack\n");
-    KernelStack = MmCreateKernelStack(FALSE);
-
-    /* Set the Process CID */
-    DPRINT("Initialliazing Thread PID and Parent Process\n");
-    Thread->Cid.UniqueProcess = Process->UniqueProcessId;
-    Thread->ThreadsProcess = Process;
+    /* Acquire rundown protection */
+    if (!ExAcquireRundownProtection (&Process->RundownProtect))
+    {
+        /* Fail */
+        ObDereferenceObject(Thread);
+        return STATUS_PROCESS_IS_TERMINATING;
+    }
 
     /* Now let the kernel initialize the context */
-    if (ThreadContext) {
-
-        /* User-mode Thread */
-
-        /* Create Teb */
-        DPRINT("Initialliazing Thread PEB\n");
-        TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
+    if (ThreadContext)
+    {
+        /* User-mode Thread, create Teb */
+        Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Failed to create the TEB. Release rundown and dereference */
+            ExReleaseRundownProtection(&Process->RundownProtect);
+            ObDereferenceObject(Thread);
+            return Status;
+        }
 
         /* Set the Start Addresses */
-        DPRINT("Initialliazing Thread Start Addresses :%x, %x\n", ThreadContext->Eip, ThreadContext->Eax);
-        Thread->StartAddress = (PVOID)ThreadContext->Eip;
-        Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
+        Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext);
+        Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext);
 
         /* Let the kernel intialize the Thread */
-        DPRINT("Initialliazing Kernel Thread\n");
-        KeInitializeThread(&Process->Pcb,
-                           &Thread->Tcb,
-                           PspUserThreadStartup,
-                           NULL,
-                           NULL,
-                           ThreadContext,
-                           TebBase,
-                           KernelStack);
-
-    } else {
-
+        Status = KeInitThread(&Thread->Tcb,
+                              NULL,
+                              PspUserThreadStartup,
+                              NULL,
+                              Thread->StartAddress,
+                              ThreadContext,
+                              TebBase,
+                              &Process->Pcb);
+    }
+    else
+    {
         /* System Thread */
-        DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine);
         Thread->StartAddress = StartRoutine;
-        Thread->SystemThread = TRUE;
+        PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
 
         /* Let the kernel intialize the Thread */
-        DPRINT("Initialliazing Kernel Thread\n");
-        KeInitializeThread(&Process->Pcb,
-                           &Thread->Tcb,
-                           PspSystemThreadStartup,
-                           StartRoutine,
-                           StartContext,
-                           NULL,
-                           NULL,
-                           KernelStack);
+        Status = KeInitThread(&Thread->Tcb,
+                              NULL,
+                              PspSystemThreadStartup,
+                              StartRoutine,
+                              StartContext,
+                              NULL,
+                              NULL,
+                              &Process->Pcb);
+    }
+
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Delete the TEB if we had done */
+        if (TebBase) MmDeleteTeb(Process, TebBase);
+
+        /* Release rundown and dereference */
+        ExReleaseRundownProtection(&Process->RundownProtect);
+        ObDereferenceObject(Thread);
+        return Status;
+    }
+
+    /* Lock the process */
+    KeEnterCriticalRegion();
+    ExAcquirePushLockExclusive(&Process->ProcessLock);
+
+    /* Make sure the proces didn't just die on us */
+    if (Process->ProcessDelete) goto Quickie;
+
+    /* Check if the thread was ours, terminated and it was user mode */
+    if ((Thread->Terminated) &&
+        (ThreadContext) &&
+        (Thread->ThreadsProcess == Process))
+    {
+        /* Cleanup, we don't want to start it up and context switch */
+        goto Quickie;
     }
 
     /*
@@ -262,88 +381,231 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
      * Note, this is the ETHREAD Thread List. It is removed in
      * ps/kill.c!PspExitThread.
      */
-    DPRINT("Inserting into Process Thread List \n");
     InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
+    Process->ActiveThreads++;
+
+    /* Start the thread */
+    KeStartThread(&Thread->Tcb);
+
+    /* Release the process lock */
+    ExReleasePushLockExclusive(&Process->ProcessLock);
+    KeLeaveCriticalRegion();
+
+    /* Release rundown */
+    ExReleaseRundownProtection(&Process->RundownProtect);
+
+    /* Notify WMI */
+    //WmiTraceProcess(Process, TRUE);
+    //WmiTraceThread(Thread, InitialTeb, TRUE);
 
     /* Notify Thread Creation */
-    DPRINT("Running Thread Notify \n");
     PspRunCreateThreadNotifyRoutines(Thread, TRUE);
 
-    /* FIXME: Use Lock */
-    DPRINT("Apcs Queueable: %d \n", Thread->Tcb.ApcQueueable);
-    Thread->Tcb.ApcQueueable = TRUE;
+    /* Reference ourselves as a keep-alive */
+    ObReferenceObjectEx(Thread, 2);
 
     /* Suspend the Thread if we have to */
-    if (CreateSuspended) {
+    if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
+
+    /* Check if we were already terminated */
+    if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
+
+    /* Create an access state */
+    Status = SeCreateAccessStateEx(NULL,
+                                   ThreadContext ?
+                                   PsGetCurrentProcess() : Process,
+                                   &LocalAccessState,
+                                   &AuxData,
+                                   DesiredAccess,
+                                   &PsThreadType->TypeInfo.GenericMapping);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Access state failed, thread is dead */
+        PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
 
-        DPRINT("Suspending Thread\n");
-        KeSuspendThread(&Thread->Tcb);
-    }
+        /* If we were suspended, wake it up */
+        if (CreateSuspended) KeResumeThread(&Thread->Tcb);
 
-    /* Reference ourselves as a keep-alive */
-    ObReferenceObject(Thread);
+        /* Dispatch thread */
+        KeReadyThread(&Thread->Tcb);
+
+        /* Dereference completely to kill it */
+        ObDereferenceObjectEx(Thread, 2);
+        return Status;
+    }
 
     /* Insert the Thread into the Object Manager */
-    DPRINT("Inserting Thread\n");
-    Status = ObInsertObject((PVOID)Thread,
-                            NULL,
+    Status = ObInsertObject(Thread,
+                            AccessState,
                             DesiredAccess,
                             0,
                             NULL,
                             &hThread);
 
-    /* Return Cid and Handle */
-    DPRINT("All worked great!\n");
-    if(NT_SUCCESS(Status)) {
+    /* Delete the access state if we had one */
+    if (AccessState) SeDeleteAccessState(AccessState);
+
+    /* Check for success */
+    if (NT_SUCCESS(Status))
+    {
+        /* Wrap in SEH to protect against bad user-mode pointers */
+        _SEH2_TRY
+        {
+            /* Return Cid and Handle */
+            if (ClientId) *ClientId = Thread->Cid;
+            *ThreadHandle = hThread;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Thread insertion failed, thread is dead */
+            PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
 
-        _SEH_TRY {
+            /* If we were suspended, wake it up */
+            if (CreateSuspended) KeResumeThread(&Thread->Tcb);
 
-            if(ClientId != NULL) {
+            /* Dispatch thread */
+            KeReadyThread(&Thread->Tcb);
 
-                *ClientId = Thread->Cid;
-            }
-            *ThreadHandle = hThread;
+            /* Dereference it, leaving only the keep-alive */
+            ObDereferenceObject(Thread);
 
-        } _SEH_HANDLE {
+            /* Close its handle, killing it */
+            ObCloseHandle(ThreadHandle, PreviousMode);
 
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        /* Thread insertion failed, thread is dead */
+        PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
 
-        } _SEH_END;
+        /* If we were suspended, wake it up */
+        if (CreateSuspended) KeResumeThread(&Thread->Tcb);
     }
 
-    /* FIXME: SECURITY */
+    /* Get the create time */
+    KeQuerySystemTime(&Thread->CreateTime);
+    ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
+
+    /* Make sure the thread isn't dead */
+    if (!Thread->DeadThread)
+    {
+        /* Get the thread's SD */
+        Status = ObGetObjectSecurity(Thread,
+                                     &SecurityDescriptor,
+                                     &SdAllocated);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Thread insertion failed, thread is dead */
+            PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
+
+            /* If we were suspended, wake it up */
+            if (CreateSuspended) KeResumeThread(&Thread->Tcb);
+
+            /* Dispatch thread */
+            KeReadyThread(&Thread->Tcb);
+
+            /* Dereference it, leaving only the keep-alive */
+            ObDereferenceObject(Thread);
+
+            /* Close its handle, killing it */
+            ObCloseHandle(ThreadHandle, PreviousMode);
+            return Status;
+        }
+
+        /* Create the subject context */
+        SubjectContext.ProcessAuditId = Process;
+        SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
+        SubjectContext.ClientToken = NULL;
+
+        /* Do the access check */
+        Result = SeAccessCheck(SecurityDescriptor,
+                               &SubjectContext,
+                               FALSE,
+                               MAXIMUM_ALLOWED,
+                               0,
+                               NULL,
+                               &PsThreadType->TypeInfo.GenericMapping,
+                               PreviousMode,
+                               &Thread->GrantedAccess,
+                               &AccessStatus);
+
+        /* Dereference the token and let go the SD */
+        ObFastDereferenceObject(&Process->Token,
+                                SubjectContext.PrimaryToken);
+        ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
+
+        /* Remove access if it failed */
+        if (!Result) Process->GrantedAccess = 0;
+
+        /* Set least some minimum access */
+        Thread->GrantedAccess |= (THREAD_TERMINATE |
+                                  THREAD_SET_INFORMATION |
+                                  THREAD_QUERY_INFORMATION);
+    }
+    else
+    {
+        /* Set the thread access mask to maximum */
+        Thread->GrantedAccess = THREAD_ALL_ACCESS;
+    }
 
     /* Dispatch thread */
-    DPRINT("About to dispatch the thread: %x!\n", &Thread->Tcb);
-    OldIrql = KeAcquireDispatcherDatabaseLock ();
-    KiUnblockThread(&Thread->Tcb, NULL, 0);
+    KeReadyThread(&Thread->Tcb);
+
+    /* Dereference it, leaving only the keep-alive */
     ObDereferenceObject(Thread);
-    KeReleaseDispatcherDatabaseLock(OldIrql);
 
     /* Return */
-    DPRINT("Returning\n");
     return Status;
+
+    /* Most annoying failure case ever, where we undo almost all manually */
+Quickie:
+    /* When we get here, the process is locked, unlock it */
+    ExReleasePushLockExclusive(&Process->ProcessLock);
+    KeLeaveCriticalRegion();
+
+    /* Uninitailize it */
+    KeUninitThread(&Thread->Tcb);
+
+    /* If we had a TEB, delete it */
+    if (TebBase) MmDeleteTeb(Process, TebBase);
+
+    /* Release rundown protection, which we also hold */
+    ExReleaseRundownProtection(&Process->RundownProtect);
+
+    /* Dereference the thread and return failure */
+    ObDereferenceObject(Thread);
+    return STATUS_PROCESS_IS_TERMINATING;
 }
 
+/* PUBLIC FUNCTIONS **********************************************************/
+
 /*
  * @implemented
  */
 NTSTATUS
-STDCALL
-PsCreateSystemThread(PHANDLE ThreadHandle,
-                     ACCESS_MASK DesiredAccess,
-                     POBJECT_ATTRIBUTES ObjectAttributes,
-                     HANDLE ProcessHandle,
-                     PCLIENT_ID ClientId,
-                     PKSTART_ROUTINE StartRoutine,
-                     PVOID StartContext)
+NTAPI
+PsCreateSystemThread(OUT PHANDLE ThreadHandle,
+                     IN ACCESS_MASK DesiredAccess,
+                     IN POBJECT_ATTRIBUTES ObjectAttributes,
+                     IN HANDLE ProcessHandle,
+                     IN PCLIENT_ID ClientId,
+                     IN PKSTART_ROUTINE StartRoutine,
+                     IN PVOID StartContext)
 {
     PEPROCESS TargetProcess = NULL;
     HANDLE Handle = ProcessHandle;
+    PAGED_CODE();
+    PSTRACE(PS_THREAD_DEBUG,
+            "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
+            ProcessHandle, StartRoutine, StartContext);
 
     /* Check if we have a handle. If not, use the System Process */
-    if (!ProcessHandle) {
-
+    if (!ProcessHandle)
+    {
         Handle = NULL;
         TargetProcess = PsInitialSystemProcess;
     }
@@ -366,7 +628,7 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsLookupThreadByThreadId(IN HANDLE ThreadId,
                          OUT PETHREAD *Thread)
 {
@@ -374,21 +636,25 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId,
     PETHREAD FoundThread;
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
     PAGED_CODE();
+    PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId);
+    KeEnterCriticalRegion();
 
     /* Get the CID Handle Entry */
-    if ((CidEntry = ExMapHandleToPointer(PspCidTable,
-                                         ThreadId)))
+    CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
+    if (CidEntry)
     {
         /* Get the Process */
-        FoundThread = CidEntry->u1.Object;
+        FoundThread = CidEntry->Object;
 
         /* Make sure it's really a process */
         if (FoundThread->Tcb.DispatcherHeader.Type == ThreadObject)
         {
-            /* Reference and return it */
-            ObReferenceObject(FoundThread);
-            *Thread = FoundThread;
-            Status = STATUS_SUCCESS;
+            /* Safe Reference and return it */
+            if (ObReferenceObjectSafe(FoundThread))
+            {
+                *Thread = FoundThread;
+                Status = STATUS_SUCCESS;
+            }
         }
 
         /* Unlock the Entry */
@@ -396,6 +662,7 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId,
     }
 
     /* Return to caller */
+    KeLeaveCriticalRegion();
     return Status;
 }
 
@@ -403,18 +670,18 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId,
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetCurrentThreadId(VOID)
 {
-    return(PsGetCurrentThread()->Cid.UniqueThread);
+    return PsGetCurrentThread()->Cid.UniqueThread;
 }
 
 /*
  * @implemented
  */
 ULONG
-STDCALL
-PsGetThreadFreezeCount(PETHREAD Thread)
+NTAPI
+PsGetThreadFreezeCount(IN PETHREAD Thread)
 {
     return Thread->Tcb.FreezeCount;
 }
@@ -423,18 +690,18 @@ PsGetThreadFreezeCount(PETHREAD Thread)
  * @implemented
  */
 BOOLEAN
-STDCALL
-PsGetThreadHardErrorsAreDisabled(PETHREAD Thread)
+NTAPI
+PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)
 {
-    return Thread->HardErrorsAreDisabled;
+    return Thread->HardErrorsAreDisabled ? TRUE : FALSE;
 }
 
 /*
  * @implemented
  */
 HANDLE
-STDCALL
-PsGetThreadId(PETHREAD Thread)
+NTAPI
+PsGetThreadId(IN PETHREAD Thread)
 {
     return Thread->Cid.UniqueThread;
 }
@@ -443,8 +710,8 @@ PsGetThreadId(PETHREAD Thread)
  * @implemented
  */
 PEPROCESS
-STDCALL
-PsGetThreadProcess(PETHREAD Thread)
+NTAPI
+PsGetThreadProcess(IN PETHREAD Thread)
 {
     return Thread->ThreadsProcess;
 }
@@ -453,8 +720,8 @@ PsGetThreadProcess(PETHREAD Thread)
  * @implemented
  */
 HANDLE
-STDCALL
-PsGetThreadProcessId(PETHREAD Thread)
+NTAPI
+PsGetThreadProcessId(IN PETHREAD Thread)
 {
     return Thread->Cid.UniqueProcess;
 }
@@ -463,8 +730,8 @@ PsGetThreadProcessId(PETHREAD Thread)
  * @implemented
  */
 HANDLE
-STDCALL
-PsGetThreadSessionId(PETHREAD Thread)
+NTAPI
+PsGetThreadSessionId(IN PETHREAD Thread)
 {
     return (HANDLE)Thread->ThreadsProcess->Session;
 }
@@ -473,8 +740,8 @@ PsGetThreadSessionId(PETHREAD Thread)
  * @implemented
  */
 PTEB
-STDCALL
-PsGetThreadTeb(PETHREAD Thread)
+NTAPI
+PsGetThreadTeb(IN PETHREAD Thread)
 {
     return Thread->Tcb.Teb;
 }
@@ -483,8 +750,8 @@ PsGetThreadTeb(PETHREAD Thread)
  * @implemented
  */
 PVOID
-STDCALL
-PsGetThreadWin32Thread(PETHREAD Thread)
+NTAPI
+PsGetThreadWin32Thread(IN PETHREAD Thread)
 {
     return Thread->Tcb.Win32Thread;
 }
@@ -493,7 +760,7 @@ PsGetThreadWin32Thread(PETHREAD Thread)
  * @implemented
  */
 KPROCESSOR_MODE
-STDCALL
+NTAPI
 PsGetCurrentThreadPreviousMode(VOID)
 {
     return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
@@ -503,7 +770,7 @@ PsGetCurrentThreadPreviousMode(VOID)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetCurrentThreadStackBase(VOID)
 {
     return PsGetCurrentThread()->Tcb.StackBase;
@@ -513,7 +780,7 @@ PsGetCurrentThreadStackBase(VOID)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetCurrentThreadStackLimit(VOID)
 {
     return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
@@ -523,59 +790,69 @@ PsGetCurrentThreadStackLimit(VOID)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 PsIsThreadTerminating(IN PETHREAD Thread)
 {
-    return (Thread->Terminated ? TRUE : FALSE);
+    return Thread->Terminated ? TRUE : FALSE;
 }
 
 /*
  * @implemented
  */
 BOOLEAN
-STDCALL
-PsIsSystemThread(PETHREAD Thread)
+NTAPI
+PsIsSystemThread(IN PETHREAD Thread)
 {
-    return (Thread->SystemThread ? TRUE: FALSE);
+    return Thread->SystemThread ? TRUE: FALSE;
 }
 
 /*
  * @implemented
  */
 BOOLEAN
-STDCALL
-PsIsThreadImpersonating(PETHREAD Thread)
+NTAPI
+PsIsThreadImpersonating(IN PETHREAD Thread)
 {
-    return Thread->ActiveImpersonationInfo;
+    return Thread->ActiveImpersonationInfo ? TRUE : FALSE;
 }
 
 /*
  * @implemented
  */
 VOID
-STDCALL
-PsSetThreadHardErrorsAreDisabled(PETHREAD Thread,
-                                 BOOLEAN HardErrorsAreDisabled)
+NTAPI
+PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread,
+                                 IN BOOLEAN HardErrorsAreDisabled)
 {
     Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
 }
 
+/*
+ * @implemented
+ */
+PVOID
+NTAPI
+PsGetCurrentThreadWin32Thread(VOID)
+{
+    return PsGetCurrentThread()->Tcb.Win32Thread;
+}
+
 /*
  * @implemented
  */
 VOID
-STDCALL
-PsSetThreadWin32Thread(PETHREAD Thread,
-                       PVOID Win32Thread)
+NTAPI
+PsSetThreadWin32Thread(IN PETHREAD Thread,
+                       IN PVOID Win32Thread)
 {
     Thread->Tcb.Win32Thread = Win32Thread;
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtCreateThread(OUT PHANDLE ThreadHandle,
                IN ACCESS_MASK DesiredAccess,
-               IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
+               IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
                IN HANDLE ProcessHandle,
                OUT PCLIENT_ID ClientId,
                IN PCONTEXT ThreadContext,
@@ -583,53 +860,48 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
                IN BOOLEAN CreateSuspended)
 {
     INITIAL_TEB SafeInitialTeb;
-
     PAGED_CODE();
+    PSTRACE(PS_THREAD_DEBUG,
+            "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
 
-    DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
-            ThreadHandle,ThreadContext);
-
-    if(KeGetPreviousMode() != KernelMode) {
-
-        _SEH_TRY {
-
-            ProbeForWrite(ThreadHandle,
-                          sizeof(HANDLE),
-                          sizeof(ULONG));
-
-            if(ClientId != NULL) {
-
-                ProbeForWrite(ClientId,
-                              sizeof(CLIENT_ID),
-                              sizeof(ULONG));
-            }
-
-            if(ThreadContext != NULL) {
-
-            ProbeForRead(ThreadContext,
-                         sizeof(CONTEXT),
-                         sizeof(ULONG));
+    /* Check if this was from user-mode */
+    if (KeGetPreviousMode() != KernelMode)
+    {
+        /* Make sure that we got a context */
+        if (!ThreadContext) return STATUS_INVALID_PARAMETER;
 
-            } else {
+        /* Protect checks */
+        _SEH2_TRY
+        {
+            /* Make sure the handle pointer we got is valid */
+            ProbeForWriteHandle(ThreadHandle);
 
-                DPRINT1("No context for User-Mode Thread!!\n");
-                return STATUS_INVALID_PARAMETER;
+            /* Check if the caller wants a client id */
+            if (ClientId)
+            {
+                /* Make sure we can write to it */
+                ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
             }
 
-            ProbeForRead(InitialTeb,
-                         sizeof(INITIAL_TEB),
-                         sizeof(ULONG));
-
-        } _SEH_HANDLE {
-
-            return _SEH_GetExceptionCode();
+            /* Make sure that the entire context is readable */
+            ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
 
-        } _SEH_END;
+            /* Check the Initial TEB */
+            ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
+            SafeInitialTeb = *InitialTeb;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        /* Use the Initial TEB as is */
+        SafeInitialTeb = *InitialTeb;
     }
-
-    /* Use probed data for the Initial TEB */
-    SafeInitialTeb = *InitialTeb;
-    InitialTeb = &SafeInitialTeb;
 
     /* Call the shared function */
     return PspCreateThread(ThreadHandle,
@@ -639,7 +911,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
                            NULL,
                            ClientId,
                            ThreadContext,
-                           InitialTeb,
+                           &SafeInitialTeb,
                            CreateSuspended,
                            NULL,
                            NULL);
@@ -649,67 +921,111 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 NtOpenThread(OUT PHANDLE ThreadHandle,
              IN ACCESS_MASK DesiredAccess,
-             IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
-             IN PCLIENT_ID ClientId  OPTIONAL)
+             IN POBJECT_ATTRIBUTES ObjectAttributes,
+             IN PCLIENT_ID ClientId OPTIONAL)
 {
-    KPROCESSOR_MODE PreviousMode  = ExGetPreviousMode();
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
     CLIENT_ID SafeClientId;
-    HANDLE hThread = 0;
-    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Attributes = 0;
+    HANDLE hThread = NULL;
+    NTSTATUS Status;
     PETHREAD Thread;
-
+    BOOLEAN HasObjectName = FALSE;
+    ACCESS_STATE AccessState;
+    AUX_ACCESS_DATA AuxData;
     PAGED_CODE();
+    PSTRACE(PS_THREAD_DEBUG,
+            "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
 
-    /* Probe the paraemeters */
-    if(PreviousMode != KernelMode)
+    /* Check if we were called from user mode */
+    if (PreviousMode != KernelMode)
     {
-        _SEH_TRY
+        /* Enter SEH for probing */
+        _SEH2_TRY
         {
-            ProbeForWrite(ThreadHandle,
-                          sizeof(HANDLE),
-                          sizeof(ULONG));
+            /* Probe the thread handle */
+            ProbeForWriteHandle(ThreadHandle);
 
-            if(ClientId != NULL)
+            /* Check for a CID structure */
+            if (ClientId)
             {
-                ProbeForRead(ClientId,
-                             sizeof(CLIENT_ID),
-                             sizeof(ULONG));
-
+                /* Probe and capture it */
+                ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
                 SafeClientId = *ClientId;
                 ClientId = &SafeClientId;
             }
+
+            /*
+             * Just probe the object attributes structure, don't capture it
+             * completely. This is done later if necessary
+             */
+            ProbeForRead(ObjectAttributes,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+            HasObjectName = (ObjectAttributes->ObjectName != NULL);
+            Attributes = ObjectAttributes->Attributes;
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
+        _SEH2_END;
+    }
+    else
+    {
+        /* Otherwise just get the data directly */
+        HasObjectName = (ObjectAttributes->ObjectName != NULL);
+        Attributes = ObjectAttributes->Attributes;
+    }
 
-        if(!NT_SUCCESS(Status)) return Status;
+    /* Can't pass both, fail */
+    if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
+
+    /* Create an access state */
+    Status = SeCreateAccessState(&AccessState,
+                                 &AuxData,
+                                 DesiredAccess,
+                                 &PsProcessType->TypeInfo.GenericMapping);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check if this is a debugger */
+    if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
+    {
+        /* Did he want full access? */
+        if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
+        {
+            /* Give it to him */
+            AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS;
+        }
+        else
+        {
+            /* Otherwise just give every other access he could want */
+            AccessState.PreviouslyGrantedAccess |=
+                AccessState.RemainingDesiredAccess;
+        }
+
+        /* The caller desires nothing else now */
+        AccessState.RemainingDesiredAccess = 0;
     }
 
     /* Open by name if one was given */
-    if (ObjectAttributes->ObjectName)
+    if (HasObjectName)
     {
         /* Open it */
         Status = ObOpenObjectByName(ObjectAttributes,
                                     PsThreadType,
-                                    NULL,
                                     PreviousMode,
-                                    DesiredAccess,
+                                    &AccessState,
+                                    0,
                                     NULL,
-                                    hThread);
+                                    &hThread);
 
-        if (Status != STATUS_SUCCESS)
-        {
-            DPRINT1("Could not open object by name\n");
-        }
-
-        /* Return Status */
-        return(Status);
+        /* Get rid of the access state */
+        SeDeleteAccessState(&AccessState);
     }
     else if (ClientId)
     {
@@ -717,84 +1033,60 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
         if (ClientId->UniqueProcess)
         {
             /* Get the Process */
-            DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess);
-            Status = PsLookupProcessThreadByCid(ClientId,
-                                                NULL,
-                                                &Thread);
+            Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread);
         }
         else
         {
             /* Get the Process */
-            DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread);
-            Status = PsLookupThreadByThreadId(ClientId->UniqueThread,
-                                              &Thread);
+            Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread);
         }
 
-        if(!NT_SUCCESS(Status))
+        /* Check if we didn't find anything */
+        if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Failure to find Thread\n");
+            /* Get rid of the access state and return */
+            SeDeleteAccessState(&AccessState);
             return Status;
         }
 
         /* Open the Thread Object */
         Status = ObOpenObjectByPointer(Thread,
-                                       ObjectAttributes->Attributes,
-                                       NULL,
-                                       DesiredAccess,
+                                       Attributes,
+                                       &AccessState,
+                                       0,
                                        PsThreadType,
                                        PreviousMode,
-                                       hThread);
-        if(!NT_SUCCESS(Status))
-        {
-            DPRINT1("Failure to open Thread\n");
-        }
+                                       &hThread);
 
-        /* Dereference the thread */
+        /* Delete the access state and dereference the thread */
+        SeDeleteAccessState(&AccessState);
         ObDereferenceObject(Thread);
     }
+    else
+    {
+        /* Neither an object name nor a client id was passed */
+        return STATUS_INVALID_PARAMETER_MIX;
+    }
 
-    /* Write back the handle */
-    if(NT_SUCCESS(Status))
+    /* Check for success */
+    if (NT_SUCCESS(Status))
     {
-        _SEH_TRY
+        /* Protect against bad user-mode pointers */
+        _SEH2_TRY
         {
+            /* Write back the handle */
             *ThreadHandle = hThread;
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            Status = _SEH_GetExceptionCode();
+            /* Get the exception code */
+            Status = _SEH2_GetExceptionCode();
         }
-        _SEH_END;
+        _SEH2_END;
     }
 
     /* Return status */
     return Status;
 }
 
-NTSTATUS
-STDCALL
-NtYieldExecution(VOID)
-{
-    KiDispatchThread(Ready);
-    return(STATUS_SUCCESS);
-}
-
-NTSTATUS
-STDCALL
-NtTestAlert(VOID)
-{
-    /* Check and Alert Thread if needed */
-    return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-KPROCESSOR_MODE
-STDCALL
-ExGetPreviousMode (VOID)
-{
-    return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
-}
-
 /* EOF */