Used HasTerminated as bitmap for flags to make difference between calling PsTerminate...
[reactos.git] / reactos / ntoskrnl / ps / kill.c
index d1fe757..1837f09 100644 (file)
-/*
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ps/kill.c
  * PURPOSE:         Terminating a thread
- * PROGRAMMER:      David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * 
+ * PROGRAMMERS:     David Welch (welch@cwcom.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ps.h>
-#include <internal/ke.h>
-#include <internal/mm.h>
-#include <internal/ob.h>
-#include <internal/port.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 /* GLOBALS *******************************************************************/
 
-extern ULONG PiNrThreads;
-extern ULONG PiNrRunnableThreads;
-extern KSPIN_LOCK PiThreadListLock;
-extern LIST_ENTRY PiThreadListHead;
+VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
+NTSTATUS STDCALL NtCallTerminatePorts(PETHREAD Thread);
+
+#define TAG_TERMINATE_APC   TAG('T', 'A', 'P', 'C')
+
+LIST_ENTRY ThreadsToReapHead;
+
+#define TERMINATE_PROC 0x1
+#define TERMINATE_APC  0x2
 
 /* FUNCTIONS *****************************************************************/
 
-VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus)
+VOID
+PsInitializeThreadReaper(VOID)
+{
+  InitializeListHead(&ThreadsToReapHead);
+}
+
+VOID
+PsReapThreads(VOID)
+{
+  KIRQL oldlvl;
+  PETHREAD Thread;
+  PLIST_ENTRY ListEntry;
+
+  oldlvl = KeAcquireDispatcherDatabaseLock();
+  while((ListEntry = RemoveHeadList(&ThreadsToReapHead)) != &ThreadsToReapHead)
+  {
+    PiNrThreadsAwaitingReaping--;
+    KeReleaseDispatcherDatabaseLock(oldlvl);
+    Thread = CONTAINING_RECORD(ListEntry, ETHREAD, TerminationPortList);
+
+    ObDereferenceObject(Thread);
+    oldlvl = KeAcquireDispatcherDatabaseLock();
+  }
+  KeReleaseDispatcherDatabaseLock(oldlvl);
+}
+
+VOID
+PsQueueThreadReap(PETHREAD Thread)
+{
+  InsertTailList(&ThreadsToReapHead, &Thread->TerminationPortList);
+  PiNrThreadsAwaitingReaping++;
+}
+
+VOID
+PiTerminateProcessThreads(PEPROCESS Process,
+                         NTSTATUS ExitStatus)
 {
    KIRQL oldlvl;
    PLIST_ENTRY current_entry;
-   PETHREAD current;
+   PETHREAD current, CurrentThread = PsGetCurrentThread();
    
    DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
          Process, ExitStatus);
+         
+   oldlvl = KeAcquireDispatcherDatabaseLock();
    
-   KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
-
-   current_entry = PiThreadListHead.Flink;
-   while (current_entry != &PiThreadListHead)
+   current_entry = Process->ThreadListHead.Flink;
+   while (current_entry != &Process->ThreadListHead)
      {
-       current = CONTAINING_RECORD(current_entry,ETHREAD,Tcb.QueueListEntry);
-       if (current->ThreadsProcess == Process &&
-           current != PsGetCurrentThread())
+       current = CONTAINING_RECORD(current_entry, ETHREAD,
+                                   ThreadListEntry);
+       if (current != CurrentThread && current->HasTerminated == 0)
          {
-            KeReleaseSpinLock(&PiThreadListLock, oldlvl);
-            DPRINT("Terminating %x\n", current);
+            DPRINT("Terminating %x, current thread: %x, "
+                   "thread's process: %x\n", current, PsGetCurrentThread(), 
+                   current->ThreadsProcess);
+             KeReleaseDispatcherDatabaseLock(oldlvl);
             PsTerminateOtherThread(current, ExitStatus);
-            KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
-            current_entry = PiThreadListHead.Flink;
+             oldlvl = KeAcquireDispatcherDatabaseLock();
+            current_entry = Process->ThreadListHead.Flink;
          }
-       current_entry = current_entry->Flink;
-     }
-
-   KeReleaseSpinLock(&PiThreadListLock, oldlvl);
-   DPRINT("Finished PiTerminateProcessThreads()\n");
-}
-
-VOID PsReapThreads(VOID)
-{
-   PLIST_ENTRY current_entry;
-   PETHREAD current;
-   KIRQL oldIrql;
-   
-//   DPRINT1("PsReapThreads()\n");
-   
-   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-   
-   current_entry = PiThreadListHead.Flink;
-   
-   while (current_entry != &PiThreadListHead)
-     {
-       current = CONTAINING_RECORD(current_entry, ETHREAD, 
-                                   Tcb.ThreadListEntry);
-       
-       current_entry = current_entry->Flink;
-       
-       if (current->Tcb.State == THREAD_STATE_TERMINATED_1)
+       else
          {
-            PEPROCESS Process = current->ThreadsProcess; 
-            NTSTATUS Status = current->ExitStatus;
-            
-            DPRINT("PsProcessType %x\n", PsProcessType);
-            ObReferenceObjectByPointer(Process, 
-                                       0, 
-                                       PsProcessType, 
-                                       KernelMode);
-            DPRINT("Reaping thread %x\n", current);
-            DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
-            current->Tcb.State = THREAD_STATE_TERMINATED_2;
-            RemoveEntryList(&current->Tcb.ProcessThreadListEntry);
-            KeReleaseSpinLock(&PiThreadListLock, oldIrql);
-            ObDereferenceObject(current);
-            KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-            if (IsListEmpty(&Process->ThreadListHead))
-              {
-                 /* 
-                  * TODO: Optimize this so it doesnt jerk the IRQL around so 
-                  * much :)
-                  */
-                 DPRINT("Last thread terminated, terminating process\n");
-                 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
-                 PiTerminateProcess(Process, Status);
-                 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-              }
-            DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
-            ObDereferenceObject(Process);
-            current_entry = PiThreadListHead.Flink;
+            current_entry = current_entry->Flink;
          }
      }
-   KeReleaseSpinLock(&PiThreadListLock, oldIrql);
+   KeReleaseDispatcherDatabaseLock(oldlvl);
+   DPRINT("Finished PiTerminateProcessThreads()\n");
 }
 
-VOID PsTerminateCurrentThread(NTSTATUS ExitStatus)
+VOID
+PsTerminateCurrentThread(NTSTATUS ExitStatus)
 /*
  * FUNCTION: Terminates the current thread
  */
 {
    KIRQL oldIrql;
    PETHREAD CurrentThread;
-   
+   PLIST_ENTRY current_entry;
+   PKMUTANT Mutant;
+   BOOLEAN Last;
+   PEPROCESS CurrentProcess;
+   SIZE_T Length = PAGE_SIZE;
+   PVOID TebBlock;
+
+   DPRINT("PsTerminateCurrentThread(ExitStatus %x)\n", ExitStatus);
+
    CurrentThread = PsGetCurrentThread();
-   
+
+   oldIrql = KeAcquireDispatcherDatabaseLock();
+   if (CurrentThread->HasTerminated & TERMINATE_PROC)
+   {
+      KeReleaseDispatcherDatabaseLock(oldIrql);
+      return;
+   }
+   CurrentThread->HasTerminated |= TERMINATE_PROC;
+   KeReleaseDispatcherDatabaseLock(oldIrql);
+
+   KeLowerIrql(PASSIVE_LEVEL);
+
+   CurrentProcess = CurrentThread->ThreadsProcess;
+
+   /* Can't terminate a thread if it attached another process */
+   if (AttachedApcEnvironment == CurrentThread->Tcb.ApcStateIndex)
+     {
+        KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG) CurrentProcess,
+                     (ULONG) CurrentThread->Tcb.ApcState.Process,
+                     (ULONG) CurrentThread->Tcb.ApcStateIndex,
+                     (ULONG) CurrentThread);
+     }
+
+   KeCancelTimer(&CurrentThread->Tcb.Timer);
+
+   oldIrql = KeAcquireDispatcherDatabaseLock();
+
    DPRINT("terminating %x\n",CurrentThread);
-   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-   
+
    CurrentThread->ExitStatus = ExitStatus;
-   KeAcquireDispatcherDatabaseLock(FALSE);
+   KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime);
+
+   /* If the ProcessoR Control Block's NpxThread points to the current thread
+    * unset it.
+    */
+   InterlockedCompareExchangePointer(&KeGetCurrentKPCR()->PrcbData.NpxThread,
+                                     NULL, ETHREAD_TO_KTHREAD(CurrentThread));
+
+   KeReleaseDispatcherDatabaseLock(oldIrql);
+   PsLockProcess(CurrentProcess, FALSE);
+
+   /* Remove the thread from the thread list of its process */
+   RemoveEntryList(&CurrentThread->ThreadListEntry);
+   Last = IsListEmpty(&CurrentProcess->ThreadListHead);
+   PsUnlockProcess(CurrentProcess);
+
+   /* Notify subsystems of the thread termination */
+   PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
+   PsTerminateWin32Thread(CurrentThread);
+
+   /* Free the TEB */
+   if(CurrentThread->Tcb.Teb)
+   {
+     DPRINT("Decommit teb at %p\n", CurrentThread->Tcb.Teb);
+     ExAcquireFastMutex(&CurrentProcess->TebLock);
+     TebBlock = MM_ROUND_DOWN(CurrentThread->Tcb.Teb, MM_VIRTMEM_GRANULARITY);
+     ZwFreeVirtualMemory(NtCurrentProcess(),
+                         (PVOID *)&CurrentThread->Tcb.Teb,
+                         &Length,
+                         MEM_DECOMMIT);
+     DPRINT("teb %p, TebBlock %p\n", CurrentThread->Tcb.Teb, TebBlock);
+     if (TebBlock != CurrentProcess->TebBlock ||
+         CurrentProcess->TebBlock == CurrentProcess->TebLastAllocated)
+       {
+         MmLockAddressSpace(&CurrentProcess->AddressSpace);
+         MmReleaseMemoryAreaIfDecommitted(CurrentProcess, &CurrentProcess->AddressSpace, TebBlock);
+         MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
+       }
+     CurrentThread->Tcb.Teb = NULL;
+     ExReleaseFastMutex(&CurrentProcess->TebLock);
+   }
+
+   /* abandon all owned mutants */
+   current_entry = CurrentThread->Tcb.MutantListHead.Flink;
+   while (current_entry != &CurrentThread->Tcb.MutantListHead)
+     {
+       Mutant = CONTAINING_RECORD(current_entry, KMUTANT,
+                                  MutantListEntry);
+       KeReleaseMutant(Mutant,
+                       MUTANT_INCREMENT,
+                       TRUE,
+                       FALSE);
+       current_entry = CurrentThread->Tcb.MutantListHead.Flink;
+     }
+
+   oldIrql = KeAcquireDispatcherDatabaseLock();
    CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
-   KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
-   KeReleaseDispatcherDatabaseLock(FALSE);
+   KiDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT);
+   KeReleaseDispatcherDatabaseLock (oldIrql);
+
+   /* The last thread shall close the door on exit */
+   if(Last)
+   {
+    /* save the last thread exit status */
+    CurrentProcess->LastThreadExitStatus = ExitStatus;
+    
+    PspRunCreateProcessNotifyRoutines(CurrentProcess, FALSE);
+    PsTerminateWin32Process(CurrentProcess);
+    PiTerminateProcess(CurrentProcess, ExitStatus);
+   }
+
+   oldIrql = KeAcquireDispatcherDatabaseLock();
+
+#ifdef _ENABLE_THRDEVTPAIR
+   ExpSwapThreadEventPair(CurrentThread, NULL); /* Release the associated eventpair object, if there was one */
+#endif /* _ENABLE_THRDEVTPAIR */
+
+   ASSERT(CurrentThread->Tcb.WaitBlockList == NULL);
    
    PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
-   KeBugCheck(0);
+   DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
+   KEBUGCHECK(0);
+}
+
+VOID STDCALL
+PiTerminateThreadRundownRoutine(PKAPC Apc)
+{
+  ExFreePool(Apc);
+}
+
+VOID STDCALL
+PiTerminateThreadKernelRoutine(PKAPC Apc,
+                              PKNORMAL_ROUTINE* NormalRoutine,
+                              PVOID* NormalContext,
+                              PVOID* SystemArgument1,
+                              PVOID* SystemArguemnt2)
+{
+  ExFreePool(Apc);
+}
+
+VOID STDCALL
+PiTerminateThreadNormalRoutine(PVOID NormalContext,
+                            PVOID SystemArgument1,
+                            PVOID SystemArgument2)
+{
+  PsTerminateCurrentThread((NTSTATUS)SystemArgument1);
 }
 
-VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus)
+VOID
+PsTerminateOtherThread(PETHREAD Thread,
+                      NTSTATUS ExitStatus)
 /*
- * FUNCTION: Terminate a thread when calling from that thread's context
+ * FUNCTION: Terminate a thread when calling from another thread's context
+ * NOTES: This function must be called with PiThreadLock held
  */
 {
-   KIRQL oldIrql;
-   
-   DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
-         Thread, ExitStatus);
-   
-   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-   if (Thread->Tcb.State == THREAD_STATE_RUNNABLE)
-     {
-       DPRINT("Removing from runnable queue\n");
-       RemoveEntryList(&Thread->Tcb.QueueListEntry);
-     }
-   DPRINT("Removing from process queue\n");
-   RemoveEntryList(&Thread->Tcb.ProcessThreadListEntry);
-   Thread->Tcb.State = THREAD_STATE_TERMINATED_2;
-   Thread->Tcb.DispatcherHeader.SignalState = TRUE;
-   KeDispatcherObjectWake(&Thread->Tcb.DispatcherHeader);
-   KeReleaseSpinLock(&PiThreadListLock, oldIrql);   
-   if (IsListEmpty(&Thread->ThreadsProcess->ThreadListHead))
-     {
-       DPRINT("Terminating associated process\n");
-       PiTerminateProcess(Thread->ThreadsProcess, ExitStatus);
-     }
-   ObDereferenceObject(Thread);
+  PKAPC Apc;
+  KIRQL OldIrql;
+
+  DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
+        Thread, ExitStatus);
+
+  OldIrql = KeAcquireDispatcherDatabaseLock();
+  if (Thread->HasTerminated & TERMINATE_APC)
+  {
+     KeReleaseDispatcherDatabaseLock (OldIrql);
+     return;
+  }
+  Thread->HasTerminated |= TERMINATE_APC;
+  KeReleaseDispatcherDatabaseLock (OldIrql);
+  Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
+  KeInitializeApc(Apc,
+                 &Thread->Tcb,
+                 OriginalApcEnvironment,
+                 PiTerminateThreadKernelRoutine,
+                 PiTerminateThreadRundownRoutine,
+                 PiTerminateThreadNormalRoutine,
+                 KernelMode,
+                 NULL);
+  KeInsertQueueApc(Apc,
+                  (PVOID)ExitStatus,
+                  NULL,
+                  IO_NO_INCREMENT);
+
+  OldIrql = KeAcquireDispatcherDatabaseLock();          
+  if (THREAD_STATE_BLOCKED == Thread->Tcb.State && UserMode == Thread->Tcb.WaitMode)
+    {
+      DPRINT("Unblocking thread\n");
+      KiAbortWaitThread((PKTHREAD)Thread, STATUS_THREAD_IS_TERMINATING);
+    }
+  KeReleaseDispatcherDatabaseLock(OldIrql); 
 }
 
-NTSTATUS STDCALL PiTerminateProcess(PEPROCESS Process,
-                                   NTSTATUS ExitStatus)
+NTSTATUS STDCALL
+PiTerminateProcess(PEPROCESS Process,
+                  NTSTATUS ExitStatus)
 {
-   DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) RC %d HC %d\n",
-          Process, ExitStatus, ObGetReferenceCount(Process),
-          ObGetHandleCount(Process));
+   KIRQL OldIrql;
+   PEPROCESS CurrentProcess;
+
+   DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n",
+          Process, ExitStatus, ObGetObjectPointerCount(Process),
+          ObGetObjectHandleCount(Process));
    
-   if (Process->Pcb.ProcessState == PROCESS_STATE_TERMINATED)
+   ObReferenceObject(Process);
+   if (InterlockedExchangeUL(&Process->Pcb.State, 
+                            PROCESS_STATE_TERMINATED) == 
+       PROCESS_STATE_TERMINATED)
      {
+        ObDereferenceObject(Process);
        return(STATUS_SUCCESS);
      }
-   
-   PiTerminateProcessThreads(Process, ExitStatus);
+   CurrentProcess = PsGetCurrentProcess();
+   if (Process != CurrentProcess)
+   {
+      KeAttachProcess(&Process->Pcb);
+   }
    ObCloseAllHandles(Process);
-   KeAcquireDispatcherDatabaseLock(FALSE);
-   Process->Pcb.ProcessState = PROCESS_STATE_TERMINATED;
+   if (Process != CurrentProcess)
+   {
+      KeDetachProcess();
+   }
+   OldIrql = KeAcquireDispatcherDatabaseLock ();
    Process->Pcb.DispatcherHeader.SignalState = TRUE;
-   KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
-   KeReleaseDispatcherDatabaseLock(FALSE);
-   if( PsGetCurrentThread()->ThreadsProcess == Process )
-     PsTerminateCurrentThread( ExitStatus );
-   DPRINT("RC %d\n", ObGetReferenceCount(Process));
+   KiDispatcherObjectWake(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT);
+   KeReleaseDispatcherDatabaseLock (OldIrql);
+   ObDereferenceObject(Process);
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS STDCALL NtTerminateProcess(IN HANDLE          ProcessHandle,
-                                   IN  NTSTATUS        ExitStatus)
+NTSTATUS STDCALL
+NtTerminateProcess(IN  HANDLE          ProcessHandle  OPTIONAL,
+                  IN   NTSTATUS        ExitStatus)
 {
    NTSTATUS Status;
    PEPROCESS Process;
    
+   PAGED_CODE();
+   
    DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
           ProcessHandle, ExitStatus);
    
    Status = ObReferenceObjectByHandle(ProcessHandle,
                                       PROCESS_TERMINATE,
                                       PsProcessType,
-                                     UserMode,
+                                     KeGetCurrentThread()->PreviousMode,
                                       (PVOID*)&Process,
                                      NULL);
    if (!NT_SUCCESS(Status))
-   {
-        return(Status);
-   }
-   
-   PiTerminateProcess(Process, ExitStatus);
+     {
+       return(Status);
+     }
+   Process->ExitStatus = ExitStatus;
+   PiTerminateProcessThreads(Process, ExitStatus);
    if (PsGetCurrentThread()->ThreadsProcess == Process)
-   {
-      ObDereferenceObject(Process);
-      PsTerminateCurrentThread(ExitStatus);
-   }
+     {
+       ObDereferenceObject(Process);
+       PsTerminateCurrentThread(ExitStatus);
+       /*
+        * We should never get here!
+        */
+       return(STATUS_SUCCESS);
+     }
    ObDereferenceObject(Process);
    return(STATUS_SUCCESS);
 }
 
 
-NTSTATUS STDCALL NtTerminateThread(IN  HANDLE          ThreadHandle,
-                                  IN   NTSTATUS        ExitStatus)
+NTSTATUS STDCALL
+NtTerminateThread(IN   HANDLE          ThreadHandle,
+                 IN    NTSTATUS        ExitStatus)
 {
    PETHREAD Thread;
    NTSTATUS Status;
    
+   PAGED_CODE();
+   
    Status = ObReferenceObjectByHandle(ThreadHandle,
                                      THREAD_TERMINATE,
                                      PsThreadType,
-                                     UserMode,
+                                     KeGetCurrentThread()->PreviousMode,
                                      (PVOID*)&Thread,
                                      NULL);
    if (Status != STATUS_SUCCESS)
@@ -241,21 +395,29 @@ NTSTATUS STDCALL NtTerminateThread(IN     HANDLE          ThreadHandle,
        return(Status);
      }
    
-   ObDereferenceObject(Thread);
-   
    if (Thread == PsGetCurrentThread())
      {
-       PsTerminateCurrentThread(ExitStatus);
+        /* dereference the thread object before we kill our thread */
+        ObDereferenceObject(Thread);
+        PsTerminateCurrentThread(ExitStatus);
+        /*
+         * We should never get here!
+         */
      }
    else
      {
        PsTerminateOtherThread(Thread, ExitStatus);
+       ObDereferenceObject(Thread);
      }
    return(STATUS_SUCCESS);
 }
 
 
-NTSTATUS STDCALL PsTerminateSystemThread(NTSTATUS ExitStatus)
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+PsTerminateSystemThread(NTSTATUS ExitStatus)
 /*
  * FUNCTION: Terminates the current thread
  * ARGUMENTS:
@@ -267,12 +429,15 @@ NTSTATUS STDCALL PsTerminateSystemThread(NTSTATUS ExitStatus)
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS STDCALL NtCallTerminatePorts(PETHREAD Thread)
+NTSTATUS STDCALL
+NtCallTerminatePorts(PETHREAD Thread)
 {
    KIRQL oldIrql;
    PLIST_ENTRY current_entry;
    PEPORT_TERMINATION_REQUEST current;
    
+   PAGED_CODE();
+   
    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
    while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
          &Thread->TerminationPortList);
@@ -283,13 +448,15 @@ NTSTATUS STDCALL NtCallTerminatePorts(PETHREAD Thread)
        KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
        LpcSendTerminationPort(current->Port, 
                               Thread->CreateTime);
+       ExFreePool(current);
        KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
      }
    KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS STDCALL NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
+NTSTATUS STDCALL
+NtRegisterThreadTerminatePort(HANDLE PortHandle)
 {
    NTSTATUS Status;
    PEPORT_TERMINATION_REQUEST Request;
@@ -297,10 +464,12 @@ NTSTATUS STDCALL NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
    KIRQL oldIrql;
    PETHREAD Thread;
    
-   Status = ObReferenceObjectByHandle(TerminationPortHandle,
+   PAGED_CODE();
+   
+   Status = ObReferenceObjectByHandle(PortHandle,
                                      PORT_ALL_ACCESS,
-                                     ExPortType,
-                                     UserMode,
+                                     LpcPortObjectType,
+                                     KeGetCurrentThread()->PreviousMode,
                                      (PVOID*)&TerminationPort,
                                      NULL);   
    if (!NT_SUCCESS(Status))
@@ -308,12 +477,20 @@ NTSTATUS STDCALL NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
        return(Status);
      }
    
-   Request = ExAllocatePool(NonPagedPool, sizeof(Request));
-   Request->Port = TerminationPort;
-   Thread = PsGetCurrentThread();
-   KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
-   InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
-   KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
-   
-   return(STATUS_SUCCESS);
+   Request = ExAllocatePool(NonPagedPool, sizeof(EPORT_TERMINATION_REQUEST));
+   if(Request != NULL)
+   {
+     Request->Port = TerminationPort;
+     Thread = PsGetCurrentThread();
+     KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
+     InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
+     KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
+
+     return(STATUS_SUCCESS);
+   }
+   else
+   {
+     ObDereferenceObject(TerminationPort);
+     return(STATUS_INSUFFICIENT_RESOURCES);
+   }
 }