fixed thread/process termination bugs that might have caused crashes. due to a apc bug gui threads terminating gui threads doesn't work. Alex is going to take care of it.
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
Modified: trunk/reactos/ntoskrnl/ps/create.c
Modified: trunk/reactos/ntoskrnl/ps/kill.c
Modified: trunk/reactos/ntoskrnl/ps/process.c

Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
--- trunk/reactos/ntoskrnl/include/internal/ps.h	2005-03-21 23:37:02 UTC (rev 14260)
+++ trunk/reactos/ntoskrnl/include/internal/ps.h	2005-03-22 02:32:14 UTC (rev 14261)
@@ -658,7 +658,7 @@
 NTSTATUS PsDeleteCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType);
 PHANDLE_TABLE_ENTRY PsLookupCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType, PVOID *Object);
 VOID PsUnlockCidHandle(PHANDLE_TABLE_ENTRY CidEntry);
-NTSTATUS PsLockProcess(PEPROCESS Process, BOOL Timeout);
+NTSTATUS PsLockProcess(PEPROCESS Process, BOOLEAN Timeout);
 VOID PsUnlockProcess(PEPROCESS Process);
 
 #define ETHREAD_TO_KTHREAD(pEThread) (&(pEThread)->Tcb)

Modified: trunk/reactos/ntoskrnl/ps/create.c
--- trunk/reactos/ntoskrnl/ps/create.c	2005-03-21 23:37:02 UTC (rev 14260)
+++ trunk/reactos/ntoskrnl/ps/create.c	2005-03-22 02:32:14 UTC (rev 14261)
@@ -372,7 +372,22 @@
   {
     return(Status);
   }
+  
+  Status = PsLockProcess(Process, FALSE);
+  if (!NT_SUCCESS(Status))
+    {
+       ObDereferenceObject(Process);
+       return(Status);
+    }
 
+  if(Process->ExitTime.QuadPart != 0)
+    {
+       PsUnlockProcess(Process);
+       return STATUS_PROCESS_IS_TERMINATING;
+    }
+
+  PsUnlockProcess(Process);
+
   Status = PsInitializeThread(Process,
 			      &Thread,
 			      ObjectAttributes,

Modified: trunk/reactos/ntoskrnl/ps/kill.c
--- trunk/reactos/ntoskrnl/ps/kill.c	2005-03-21 23:37:02 UTC (rev 14260)
+++ trunk/reactos/ntoskrnl/ps/kill.c	2005-03-22 02:32:14 UTC (rev 14261)
@@ -103,11 +103,9 @@
             if (!Thread->HasTerminated) {
         
                 Thread->HasTerminated = TRUE;
+
                 /* Terminate it by APC */
                 PspTerminateThreadByPointer(Thread, ExitStatus);
-                
-                /* Unsuspend it */
-                KeForceResumeThread(&Thread->Tcb);
             }
         }
     }
@@ -181,7 +179,7 @@
     PVOID TebBlock;
     PTERMINATION_PORT TerminationPort;
 
-    DPRINT("PsTerminateCurrentThread(ExitStatus %x)\n", ExitStatus);
+    DPRINT("PsTerminateCurrentThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
 
     /* Get the Current Thread and Process */
     CurrentThread = PsGetCurrentThread();
@@ -202,6 +200,10 @@
 
     /* Run Thread Notify Routines before we desintegrate the thread */
     PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
+    
+    /* Set the Exit Status and Exit Time */
+    CurrentThread->ExitStatus = ExitStatus;
+    KeQuerySystemTime(&CurrentThread->ExitTime);
 
     /* Lock the Process before we modify its thread entries */
     PsLockProcess(CurrentProcess, FALSE);
@@ -213,8 +215,13 @@
     /* Set the last Thread Exit Status */
     CurrentProcess->LastThreadExitStatus = ExitStatus;
     
-    /* Unlock the Process */
-    PsUnlockProcess(CurrentProcess);
+    if (Last) {
+
+       /* Save the Exit Time if not already done by NtTerminateProcess. This
+          happens when the last thread just terminates without explicitly
+          terminating the process. */
+       CurrentProcess->ExitTime = CurrentThread->ExitTime;
+    }
     
     /* Check if the process has a debug port */
     if (CurrentProcess->DebugPort) {
@@ -239,22 +246,15 @@
         DPRINT("TerminationPort: %p\n", TerminationPort);
     }
       
-    /* Rundown Win32 Structures */
-    PsTerminateWin32Thread(CurrentThread);
+    /* Rundown Win32 Structures */DPRINT1("Terminating win32 thread 0x%x (proc 0x%x)\n", CurrentThread, CurrentThread->ThreadsProcess);
+    PsTerminateWin32Thread(CurrentThread);if (Last) {DPRINT1("Terminating win32 process 0x%x (thread 0x%x)\n", CurrentProcess, CurrentThread); }
     if (Last) PsTerminateWin32Process(CurrentProcess);
    
     /* Cancel I/O for the thread. */
     IoCancelThreadIo(CurrentThread);
    
-    /* Rundown Timers */
-    ExTimerRundown();
-    KeCancelTimer(&CurrentThread->Tcb.Timer);
-   
     /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */
     //CmNotifyRunDown(CurrentThread);
-   
-    /* Rundown Mutexes */
-    KeRundownThread();
      
     /* Free the TEB */
     if(CurrentThread->Tcb.Teb) {
@@ -282,19 +282,25 @@
         ExReleaseFastMutex(&CurrentProcess->TebLock);
     }
    
-    /* Set the Exit Status and Exit Time */
-    CurrentThread->ExitStatus = ExitStatus;
-    KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime);
-       
+    /* The last Thread shuts down the Process */if (Last) {DPRINT1("calling PspExitProcess\n");}
+    if (Last) PspExitProcess(CurrentProcess);
+    
+    /* Unlock the Process */DPRINT1("Released process 0x%x lock by 0x%x\n", CurrentProcess, PsGetCurrentThread());
+    PsUnlockProcess(CurrentProcess);
+    
+    /* Rundown Timers */
+    ExTimerRundown();
+    KeCancelTimer(&CurrentThread->Tcb.Timer);
+    
     /* If the Processor Control Block's NpxThread points to the current thread
      * unset it.
      */
     InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread,
                                       NULL,
                                       (PKPROCESS)CurrentThread);
-   
-    /* The last Thread shuts down the Process */
-    if (Last) PspExitProcess(CurrentProcess);
+    
+    /* Rundown Mutexes */
+    KeRundownThread();
 
     /* Terminate the Thread from the Scheduler */
     KeTerminateThread(0);
@@ -312,11 +318,16 @@
 {
     NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
     
+    DPRINT("PsExitSpecialApc called: 0x%x\n", PsGetCurrentThread());
+    
     /* Free the APC */
     ExFreePool(Apc);
     
     /* Terminate the Thread */
     PspExitThread(ExitStatus);
+    
+    /* we should never reach this point! */
+    KEBUGCHECK(0);
 }
 
 VOID 
@@ -330,6 +341,9 @@
      */
     DPRINT1("APC2\n");
     PspExitThread((NTSTATUS)NormalContext);
+    
+    /* we should never reach this point! */
+    KEBUGCHECK(0);
 }
 
 /*
@@ -347,9 +361,12 @@
     
     /* Check if we are already in the right context */
     if (PsGetCurrentThread() == Thread) {
-    
+
         /* Directly terminate the thread */
         PspExitThread(ExitStatus);
+
+        /* we should never reach this point! */
+        KEBUGCHECK(0);
     }
     
     /* Allocate the APC */
@@ -388,12 +405,12 @@
     RemoveEntryList(&Process->ProcessListEntry);
     ExReleaseFastMutex(&PspActiveProcessMutex);
     
+    /* close all handles associated with our process, this needs to be done
+       when the last thread still runs */
     ObKillProcess(Process);
+
     KeSetProcess(&Process->Pcb, IO_NO_INCREMENT);
-
-    /* NOTE: This dereference corresponds to reference in NtTerminateProcess. */
-    ObDereferenceObject(Process);
-
+    
     return(STATUS_SUCCESS);
 }
 
@@ -424,38 +441,47 @@
     }
     
     PsLockProcess(Process, FALSE);
-
-    if(Process->ExitTime.QuadPart) {
-        
-        DPRINT1("Process has an exit time!\n");
-        KeLeaveCriticalRegion();
-        return STATUS_PROCESS_IS_TERMINATING;
+    
+    if(Process->ExitTime.QuadPart != 0)
+    {
+      PsUnlockProcess(Process);
+      return STATUS_PROCESS_IS_TERMINATING;
     }
     
     /* Terminate all the Process's Threads */
     PspTerminateProcessThreads(Process, ExitStatus);
-
-    /* Save the Exit Time */
-    KeQuerySystemTime(&Process->ExitTime);
-
-    PsUnlockProcess(Process);
             
     /* Only master thread remains... kill it off */
     if (PsGetCurrentThread()->ThreadsProcess == Process) {
         
-        /*
-         * NOTE: Dereferencing of the Process structure takes place in
-         * PspExitProcess. If we would do it here the Win32 Process
-         * information would be destroyed before the Win32 Destroy
-         * thread/process callback is called.
-         */
+        /* set the exit time as we're about to release the process lock before
+           we kill ourselves to prevent threads outside of our process trying
+           to kill us */
+        KeQuerySystemTime(&Process->ExitTime);
         
+        PsUnlockProcess(Process);
+        
+        /* we can safely dereference the process because the current thread
+           holds a reference to it until it gets reaped */
+        ObDereferenceObject(Process);
+        
+        /* now the other threads get a chance to terminate, we don't wait but
+           just kill ourselves right now. The process will be run down when the
+           last thread terminates */
+
         PspExitThread(ExitStatus);
-        return(STATUS_SUCCESS);
+        
+        /* we should never reach this point! */
+        KEBUGCHECK(0);
     }
+    else
+    {
+        /* unlock and dereference the process so the threads can kill themselves */
+        PsUnlockProcess(Process);
+        ObDereferenceObject(Process);
+        DPRINT1("Terminated foreign process 0x%x\n", Process);
+    }
     
-    /* If we took this path instead, then do the same as above */ 
-    ObDereferenceObject(Process);
     return(STATUS_SUCCESS);
 }
 
@@ -498,17 +524,20 @@
          
              /* Terminate it */
              PspTerminateThreadByPointer(Thread, ExitStatus);
-             
-             /* Resume it */
-             KeForceResumeThread(&Thread->Tcb);
          }
         
     } else {
+
+        /* it's safe to dereference thread, there's at least the keep-alive
+           reference which will be removed by the thread reaper causing the
+           thread to be finally destroyed */
         ObDereferenceObject(Thread);
             
         /* Terminate him, he's ours */
         PspExitThread(ExitStatus);
-        /* We do never reach this point */        
+
+        /* We do never reach this point */
+        KEBUGCHECK(0);
     }
     
     /* Dereference the Thread and return */
@@ -534,6 +563,10 @@
         
     /* Terminate it for real */
     PspExitThread(ExitStatus);
+    
+    /* we should never reach this point! */
+    KEBUGCHECK(0);
+    
     return(STATUS_SUCCESS);
 }
 

Modified: trunk/reactos/ntoskrnl/ps/process.c
--- trunk/reactos/ntoskrnl/ps/process.c	2005-03-21 23:37:02 UTC (rev 14260)
+++ trunk/reactos/ntoskrnl/ps/process.c	2005-03-22 02:32:14 UTC (rev 14261)
@@ -1645,7 +1645,7 @@
 }
 
 NTSTATUS
-PsLockProcess(PEPROCESS Process, BOOL Timeout)
+PsLockProcess(PEPROCESS Process, BOOLEAN Timeout)
 {
   ULONG Attempts = 0;
   PKTHREAD PrevLockOwner;
@@ -1689,9 +1689,8 @@
           }
 #endif
           KeLeaveCriticalRegion();
-
+          break;
         }
-        break;
       }
       else
       {