Used HasTerminated as bitmap for flags to make difference between calling PsTerminate...
[reactos.git] / reactos / ntoskrnl / ps / kill.c
index 8c6598a..1837f09 100644 (file)
@@ -1,12 +1,11 @@
-/* $Id: kill.c,v 1.83 2004/11/13 22:27:15 hbirr Exp $
+/* $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 *****************************************************************/
 
 /* GLOBALS *******************************************************************/
 
-extern KSPIN_LOCK PiThreadLock;
-
 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
@@ -40,19 +41,17 @@ PsReapThreads(VOID)
   PETHREAD Thread;
   PLIST_ENTRY ListEntry;
 
-  KeAcquireSpinLock(&PiThreadLock, &oldlvl);
+  oldlvl = KeAcquireDispatcherDatabaseLock();
   while((ListEntry = RemoveHeadList(&ThreadsToReapHead)) != &ThreadsToReapHead)
   {
     PiNrThreadsAwaitingReaping--;
-    KeReleaseSpinLock(&PiThreadLock, oldlvl);
-    
+    KeReleaseDispatcherDatabaseLock(oldlvl);
     Thread = CONTAINING_RECORD(ListEntry, ETHREAD, TerminationPortList);
 
     ObDereferenceObject(Thread);
-
-    KeAcquireSpinLock(&PiThreadLock, &oldlvl);
+    oldlvl = KeAcquireDispatcherDatabaseLock();
   }
-  KeReleaseSpinLock(&PiThreadLock, oldlvl);
+  KeReleaseDispatcherDatabaseLock(oldlvl);
 }
 
 VOID
@@ -72,9 +71,9 @@ PiTerminateProcessThreads(PEPROCESS Process,
    
    DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
          Process, ExitStatus);
+         
+   oldlvl = KeAcquireDispatcherDatabaseLock();
    
-   KeAcquireSpinLock(&PiThreadLock, &oldlvl);
-
    current_entry = Process->ThreadListHead.Flink;
    while (current_entry != &Process->ThreadListHead)
      {
@@ -85,9 +84,9 @@ PiTerminateProcessThreads(PEPROCESS Process,
             DPRINT("Terminating %x, current thread: %x, "
                    "thread's process: %x\n", current, PsGetCurrentThread(), 
                    current->ThreadsProcess);
-            KeReleaseSpinLock(&PiThreadLock, oldlvl);
+             KeReleaseDispatcherDatabaseLock(oldlvl);
             PsTerminateOtherThread(current, ExitStatus);
-            KeAcquireSpinLock(&PiThreadLock, &oldlvl);
+             oldlvl = KeAcquireDispatcherDatabaseLock();
             current_entry = Process->ThreadListHead.Flink;
          }
        else
@@ -95,7 +94,7 @@ PiTerminateProcessThreads(PEPROCESS Process,
             current_entry = current_entry->Flink;
          }
      }
-   KeReleaseSpinLock(&PiThreadLock, oldlvl);
+   KeReleaseDispatcherDatabaseLock(oldlvl);
    DPRINT("Finished PiTerminateProcessThreads()\n");
 }
 
@@ -114,9 +113,21 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
    SIZE_T Length = PAGE_SIZE;
    PVOID TebBlock;
 
-   KeLowerIrql(PASSIVE_LEVEL);
+   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 */
@@ -128,19 +139,29 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
                      (ULONG) CurrentThread);
      }
 
-   KeAcquireSpinLock(&PiThreadLock, &oldIrql);
+   KeCancelTimer(&CurrentThread->Tcb.Timer);
+
+   oldIrql = KeAcquireDispatcherDatabaseLock();
 
    DPRINT("terminating %x\n",CurrentThread);
 
    CurrentThread->ExitStatus = ExitStatus;
    KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime);
-   KeCancelTimer(&CurrentThread->Tcb.Timer);
+
+   /* 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);
-
-   KeReleaseSpinLock(&PiThreadLock, oldIrql);
+   PsUnlockProcess(CurrentProcess);
 
    /* Notify subsystems of the thread termination */
    PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
@@ -164,6 +185,7 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
          MmReleaseMemoryAreaIfDecommitted(CurrentProcess, &CurrentProcess->AddressSpace, TebBlock);
          MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
        }
+     CurrentThread->Tcb.Teb = NULL;
      ExReleaseFastMutex(&CurrentProcess->TebLock);
    }
 
@@ -182,24 +204,28 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
 
    oldIrql = KeAcquireDispatcherDatabaseLock();
    CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
-   KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
+   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);
    }
 
-   KeAcquireSpinLock(&PiThreadLock, &oldIrql);
+   oldIrql = KeAcquireDispatcherDatabaseLock();
 
 #ifdef _ENABLE_THRDEVTPAIR
    ExpSwapThreadEventPair(CurrentThread, NULL); /* Release the associated eventpair object, if there was one */
 #endif /* _ENABLE_THRDEVTPAIR */
-   KeRemoveAllWaitsThread (CurrentThread, STATUS_UNSUCCESSFUL, FALSE);
 
+   ASSERT(CurrentThread->Tcb.WaitBlockList == NULL);
+   
    PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
    DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
    KEBUGCHECK(0);
@@ -226,7 +252,7 @@ PiTerminateThreadNormalRoutine(PVOID NormalContext,
                             PVOID SystemArgument1,
                             PVOID SystemArgument2)
 {
-  PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus);
+  PsTerminateCurrentThread((NTSTATUS)SystemArgument1);
 }
 
 VOID
@@ -238,13 +264,19 @@ PsTerminateOtherThread(PETHREAD Thread,
  */
 {
   PKAPC Apc;
-  NTSTATUS Status;
+  KIRQL OldIrql;
 
   DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
         Thread, ExitStatus);
-  
-  Thread->HasTerminated = TRUE;
-  Thread->ExitStatus = 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,
@@ -255,15 +287,17 @@ PsTerminateOtherThread(PETHREAD Thread,
                  KernelMode,
                  NULL);
   KeInsertQueueApc(Apc,
-                  NULL,
+                  (PVOID)ExitStatus,
                   NULL,
                   IO_NO_INCREMENT);
+
+  OldIrql = KeAcquireDispatcherDatabaseLock();          
   if (THREAD_STATE_BLOCKED == Thread->Tcb.State && UserMode == Thread->Tcb.WaitMode)
     {
       DPRINT("Unblocking thread\n");
-      Status = STATUS_THREAD_IS_TERMINATING;
-      KeRemoveAllWaitsThread(Thread, Status, TRUE);
+      KiAbortWaitThread((PKTHREAD)Thread, STATUS_THREAD_IS_TERMINATING);
     }
+  KeReleaseDispatcherDatabaseLock(OldIrql); 
 }
 
 NTSTATUS STDCALL
@@ -278,8 +312,8 @@ PiTerminateProcess(PEPROCESS Process,
           ObGetObjectHandleCount(Process));
    
    ObReferenceObject(Process);
-   if (InterlockedExchange((PLONG)&Process->Pcb.State, 
-                          PROCESS_STATE_TERMINATED) == 
+   if (InterlockedExchangeUL(&Process->Pcb.State, 
+                            PROCESS_STATE_TERMINATED) == 
        PROCESS_STATE_TERMINATED)
      {
         ObDereferenceObject(Process);
@@ -297,7 +331,7 @@ PiTerminateProcess(PEPROCESS Process,
    }
    OldIrql = KeAcquireDispatcherDatabaseLock ();
    Process->Pcb.DispatcherHeader.SignalState = TRUE;
-   KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
+   KiDispatcherObjectWake(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT);
    KeReleaseDispatcherDatabaseLock (OldIrql);
    ObDereferenceObject(Process);
    return(STATUS_SUCCESS);
@@ -310,6 +344,8 @@ NtTerminateProcess(IN       HANDLE          ProcessHandle  OPTIONAL,
    NTSTATUS Status;
    PEPROCESS Process;
    
+   PAGED_CODE();
+   
    DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
           ProcessHandle, ExitStatus);
    
@@ -346,6 +382,8 @@ NtTerminateThread(IN        HANDLE          ThreadHandle,
    PETHREAD Thread;
    NTSTATUS Status;
    
+   PAGED_CODE();
+   
    Status = ObReferenceObjectByHandle(ThreadHandle,
                                      THREAD_TERMINATE,
                                      PsThreadType,
@@ -398,6 +436,8 @@ NtCallTerminatePorts(PETHREAD Thread)
    PLIST_ENTRY current_entry;
    PEPORT_TERMINATION_REQUEST current;
    
+   PAGED_CODE();
+   
    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
    while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
          &Thread->TerminationPortList);
@@ -424,9 +464,11 @@ NtRegisterThreadTerminatePort(HANDLE PortHandle)
    KIRQL oldIrql;
    PETHREAD Thread;
    
+   PAGED_CODE();
+   
    Status = ObReferenceObjectByHandle(PortHandle,
                                      PORT_ALL_ACCESS,
-                                     ExPortType,
+                                     LpcPortObjectType,
                                      KeGetCurrentThread()->PreviousMode,
                                      (PVOID*)&TerminationPort,
                                      NULL);