- Massive re-write of some parts of Ps, based on a patch I wrote almost a year ago...
authorAlex Ionescu <aionescu@gmail.com>
Sun, 9 Jul 2006 18:54:13 +0000 (18:54 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Sun, 9 Jul 2006 18:54:13 +0000 (18:54 +0000)
    - Architectural changes to match information in Windows Internals 4 and other documented sources of information (Windows Internals II by Probert). Code should match Win2003 layout.
    - Handle almost any possible process/thread sub structure and add its cleanup code stubs, so that when we actually implement them, we won't forget to clean them up in the process code.
    - Add interlocked usage of process and thread flags in order to make everything more thread-safe.
    - Better handle cases where threads die instantly, race conditions, and other weird issues.
    - Better handle process termination and thread termination.
    - Implement NtCreateProcessEx and update PspCreateProcess/NtCreateProcess.
    - Improve cleanup of process object in PspProcessDelete.
    - Optimize some things like User Thread startup.
    - Add some extra asserts, paged_code checks and also user-mode security check.
    - Implement helper API PsGetNextProcessThread
    - Optimize thread reaper (thanks Filip)
    - Do proper referencing/dereferencing of thread/processes (thanks Thomas)
    - Document FIXMEs needed for Ps code to be up to standards and complete.

svn path=/trunk/; revision=22976

32 files changed:
reactos/ntoskrnl/dbgk/dbgkutil.c
reactos/ntoskrnl/dbgk/debug.c
reactos/ntoskrnl/ex/power.c
reactos/ntoskrnl/include/internal/dbgk.h
reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/include/internal/lpc.h
reactos/ntoskrnl/include/internal/mm.h
reactos/ntoskrnl/include/internal/ntoskrnl.h
reactos/ntoskrnl/include/internal/ob.h
reactos/ntoskrnl/include/internal/po.h
reactos/ntoskrnl/include/internal/ps.h
reactos/ntoskrnl/include/internal/se.h
reactos/ntoskrnl/include/internal/tag.h
reactos/ntoskrnl/ke/kthread.c
reactos/ntoskrnl/ke/process.c
reactos/ntoskrnl/lpc/close.c
reactos/ntoskrnl/lpc/send.c
reactos/ntoskrnl/mm/mm.c
reactos/ntoskrnl/mm/process.c
reactos/ntoskrnl/ntoskrnl.mc
reactos/ntoskrnl/ob/obhandle.c
reactos/ntoskrnl/ob/obname.c
reactos/ntoskrnl/ob/obref.c
reactos/ntoskrnl/po/power.c
reactos/ntoskrnl/ps/job.c
reactos/ntoskrnl/ps/kill.c
reactos/ntoskrnl/ps/process.c
reactos/ntoskrnl/ps/psmgr.c
reactos/ntoskrnl/ps/security.c
reactos/ntoskrnl/ps/thread.c
reactos/ntoskrnl/ps/win32.c
reactos/ntoskrnl/se/audit.c

index b8aec4c..550512c 100644 (file)
@@ -54,4 +54,18 @@ DbgkCreateThread(PVOID StartAddress)
 #endif
 }
 
+VOID
+NTAPI
+DbgkExitProcess(IN NTSTATUS ExitStatus)
+{
+    /* FIXME */
+}
+
+VOID
+NTAPI
+DbgkExitThread(IN NTSTATUS ExitStatus)
+{
+    /* FIXME */
+}
+
 /* EOF */
index 1c67cb1..ab8fbdd 100644 (file)
 #include <internal/debug.h>
 
 POBJECT_TYPE DbgkDebugObjectType;
+
 /* FUNCTIONS *****************************************************************/
 
+VOID
+NTAPI
+DbgkCopyProcessDebugPort(IN PEPROCESS Process,
+                         IN PEPROCESS Parent)
+{
+    /* FIXME: Implement */
+}
+
 NTSTATUS
 NTAPI
 NtCreateDebugObject(OUT PHANDLE DebugHandle,
index 3dd62db..fe0fe8b 100644 (file)
@@ -153,7 +153,7 @@ ShutdownThreadMain(PVOID Context)
                                           sizeof(PCH))]);
      }
 
-   PiShutdownProcessManager();
+   PspShutdownProcessManager();
    Waittime.QuadPart = (LONGLONG)-10000000; /* 1sec */
    KeDelayExecutionThread(KernelMode, FALSE, &Waittime);
 
index d50b48f..a1a6226 100644 (file)
@@ -5,6 +5,21 @@ VOID
 STDCALL
 DbgkCreateThread(PVOID StartAddress);
 
+VOID
+NTAPI
+DbgkExitProcess(IN NTSTATUS ExitStatus);
+
+VOID
+NTAPI
+DbgkExitThread(IN NTSTATUS ExitStatus);
+
+VOID
+NTAPI
+DbgkCopyProcessDebugPort(
+    IN PEPROCESS Process,
+    IN PEPROCESS Parent
+);
+
 #endif
 
 /* EOF */
index 65a450c..b45333f 100644 (file)
@@ -498,7 +498,8 @@ ULONG
 STDCALL
 KeSetProcess(
     struct _KPROCESS* Process,
-    KPRIORITY Increment
+    KPRIORITY Increment,
+    BOOLEAN InWait
 );
 
 VOID
index 5755fd2..af40b0e 100644 (file)
@@ -88,7 +88,7 @@ LpcSendTerminationPort(
     LARGE_INTEGER CreationTime
 );
 
-/* Code in ntoskrnl/lpc/close.h */
+/* Code in ntoskrnl/lpc/close.c */
 
 VOID 
 STDCALL
@@ -104,6 +104,10 @@ VOID
 STDCALL
 LpcpDeletePort(IN PVOID ObjectBody);
 
+VOID
+NTAPI
+LpcExitThread(IN PETHREAD Thread);
+
 /* Code in ntoskrnl/lpc/queue.c */
 
 VOID
index 4829e24..9b9de19 100644 (file)
@@ -619,7 +619,7 @@ MmShowOutOfSpaceMessagePagingFile(VOID);
 NTSTATUS
 STDCALL
 MmCreateProcessAddressSpace(
-    IN struct _EPROCESS* Process,
+    IN PEPROCESS Process,
     IN PROS_SECTION_OBJECT Section OPTIONAL
 );
 
@@ -627,7 +627,7 @@ NTSTATUS
 STDCALL
 MmCreatePeb(struct _EPROCESS *Process);
 
-struct _TEB*
+PTEB
 STDCALL
 MmCreateTeb(
     struct _EPROCESS *Process,
@@ -639,9 +639,21 @@ VOID
 STDCALL
 MmDeleteTeb(
     struct _EPROCESS *Process,
-    struct _TEB* Teb
+    PTEB Teb
 );
 
+VOID
+NTAPI
+MmCleanProcessAddressSpace(IN PEPROCESS Process);
+
+NTSTATUS
+NTAPI
+MmDeleteProcessAddressSpace(IN PEPROCESS Process);
+
+ULONG
+NTAPI
+MmGetSessionLocaleId(VOID);
+
 /* i386/pfault.c *************************************************************/
 
 NTSTATUS
index 65b6e2b..4cfbc4f 100644 (file)
@@ -101,6 +101,26 @@ InterlockedAnd(IN OUT LONG volatile *Target,
     return j;
 }
 
+FORCEINLINE
+LONG
+InterlockedOr(IN OUT LONG volatile *Target,
+              IN LONG Set)
+{
+    LONG i;
+    LONG j;
+
+    j = *Target;
+    do {
+        i = j;
+        j = InterlockedCompareExchange((PLONG)Target,
+                                       i | Set,
+                                       i);
+
+    } while (i != j);
+
+    return j;
+}
+
 /*
  * generic information class probing code
  */
index 275d14f..f1af062 100644 (file)
@@ -198,6 +198,17 @@ ObpReapObject(
     IN PVOID Unused
 );
 
+VOID
+NTAPI
+ObDereferenceDeviceMap(IN PEPROCESS Process);
+
+VOID
+NTAPI
+ObInheritDeviceMap(
+    IN PEPROCESS Parent,
+    IN PEPROCESS Process
+);
+
 VOID
 FASTCALL
 ObpSetPermanentObject(
@@ -211,9 +222,12 @@ ObpDeleteNameCheck(
     IN PVOID Object
 );
 
-//
-// Security functions
-//
+VOID
+NTAPI
+ObClearProcessHandleTable(IN PEPROCESS Process);
+
+/* Security descriptor cache functions */
+
 NTSTATUS
 NTAPI
 ObpInitSdCache(
index dccdf8c..a96f8a5 100644 (file)
@@ -14,4 +14,8 @@ NTSTATUS
 NTAPI
 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState);
 
+VOID
+NTAPI
+PopCleanupPowerState(IN PPOWER_STATE PowerState);
+
 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_PO_H */
index e696888..76137d6 100644 (file)
@@ -40,7 +40,7 @@ PiInitProcessManager(VOID);
 
 VOID
 NTAPI
-PiShutdownProcessManager(VOID);
+PspShutdownProcessManager(VOID);
 
 VOID
 NTAPI
@@ -172,6 +172,13 @@ PspAssignPrimaryToken(
     HANDLE TokenHandle
 );
 
+PETHREAD
+NTAPI
+PsGetNextProcessThread(
+    IN PEPROCESS Process,
+    IN PETHREAD Thread OPTIONAL
+);
+
 VOID
 STDCALL
 PsExitSpecialApc(
@@ -218,14 +225,15 @@ VOID
 STDCALL
 PspExitThread(NTSTATUS ExitStatus);
 
-VOID
+NTSTATUS
 STDCALL
 PspTerminateThreadByPointer(
     PETHREAD Thread,
-    NTSTATUS ExitStatus
+    NTSTATUS ExitStatus,
+    BOOLEAN bSelf
 );
 
-VOID
+NTSTATUS
 NTAPI
 PsUnfreezeOtherThread(PETHREAD Thread);
 
@@ -287,9 +295,10 @@ VOID
 NTAPI
 PsInitialiseSuspendImplementation(VOID);
 
-NTSTATUS
+VOID
 STDCALL
-PspExitProcess(PEPROCESS Process);
+PspExitProcess(BOOLEAN LastThread,
+               PEPROCESS Process);
 
 VOID
 STDCALL
@@ -376,4 +385,34 @@ VOID
 NTAPI
 PsUnlockProcess(PEPROCESS Process);
 
+VOID
+NTAPI
+PspRemoveProcessFromJob(
+    IN PEPROCESS Process,
+    IN PEJOB Job
+);
+
+NTSTATUS
+NTAPI
+PspDeleteLdt(IN PEPROCESS Process);
+
+NTSTATUS
+NTAPI
+PspDeleteVdmObjects(IN PEPROCESS Process);
+
+VOID
+NTAPI
+PspDeleteProcessSecurity(IN PEPROCESS Process);
+
+VOID
+NTAPI
+PspDeleteThreadSecurity(IN PETHREAD Thread);
+
+VOID
+NTAPI
+PspExitProcessFromJob(
+    IN PEJOB Job,
+    IN PEPROCESS Process
+);
+
 #endif /* __INCLUDE_INTERNAL_PS_H */
index 3dc8c06..b6808d3 100644 (file)
@@ -136,6 +136,14 @@ PTOKEN
 STDCALL
 SepCreateSystemProcessToken(VOID);
 
+BOOLEAN
+NTAPI
+SeDetailedAuditingWithToken(IN PTOKEN Token);
+
+VOID
+NTAPI
+SeAuditProcessExit(IN PEPROCESS Process);
+
 NTSTATUS
 NTAPI
 SeExchangePrimaryToken(
index d7657d2..01e32c4 100644 (file)
 #define TAG_LPC_MESSAGE   TAG('L', 'p', 'c', 'M')
 #define TAG_LPC_ZONE      TAG('L', 'p', 'c', 'Z')
 
+/* Se Process Audit */
+#define TAG_SEPA          TAG('S', 'e', 'P', 'a')
+
 #endif /* _NTOSKRNL_TAG_H */
index 145e6b6..073462f 100644 (file)
@@ -22,7 +22,7 @@ extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
 LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
 static ULONG PriorityListMask = 0;
 ULONG IdleProcessorMask = 0;
-extern PETHREAD PspReaperList;
+extern LIST_ENTRY PspReaperListHead;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -1383,34 +1383,56 @@ KeTerminateThread(IN KPRIORITY Increment)
 {
     KIRQL OldIrql;
     PKTHREAD Thread = KeGetCurrentThread();
+    PKPROCESS Process = Thread->ApcState.Process;
+    PLIST_ENTRY *ListHead;
+    PETHREAD Entry, SavedEntry;
+    PETHREAD *ThreadAddr;
+    DPRINT("Terminating\n");
 
     /* Lock the Dispatcher Database and the APC Queue */
-    DPRINT("Terminating\n");
+    ASSERT_IRQL(DISPATCH_LEVEL);
     OldIrql = KeAcquireDispatcherDatabaseLock();
+    ASSERT(Thread->SwapBusy == FALSE);
 
-    /* Remove the thread from the list */
-    RemoveEntryList(&Thread->ThreadListEntry);
+    /* Make sure we won't get Swapped */
+    Thread->SwapBusy = TRUE;
+
+    /* Save the Kernel and User Times */
+    Process->KernelTime += Thread->KernelTime;
+    Process->UserTime += Thread->UserTime;
+
+    /* Get the current entry and our Port */
+    Entry = (PETHREAD)PspReaperListHead.Flink;
+    ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
+
+    /* Add it to the reaper's list */
+    do
+    {
+        /* Get the list head */
+        ListHead = &PspReaperListHead.Flink;
+
+        /* Link ourselves */
+        *ThreadAddr = Entry;
+        SavedEntry = Entry;
 
-    /* Insert into the Reaper List */
-    DPRINT("List: %p\n", PspReaperList);
-    ((PETHREAD)Thread)->ReaperLink = PspReaperList;
-    PspReaperList = (PETHREAD)Thread;
-    DPRINT("List: %p\n", PspReaperList);
+        /* Now try to do the exchange */
+        Entry = InterlockedCompareExchangePointer(ListHead, ThreadAddr, Entry);
 
-    /* Check if it's active */
-    if (PspReaping == FALSE) {
+        /* Break out if the change was succesful */
+    } while (Entry != SavedEntry);
 
-        /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
-        PspReaping = TRUE;
-        DPRINT("Terminating\n");
+    /* Check if the reaper wasn't active */
+    if (!Entry)
+    {
+        /* Activate it as a work item, directly through its Queue */
         KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
                       &PspReaperWorkItem.List,
                       FALSE);
     }
 
     /* Handle Kernel Queues */
-    if (Thread->Queue) {
-
+    if (Thread->Queue)
+    {
         DPRINT("Waking Queue\n");
         RemoveEntryList(&Thread->QueueListEntry);
         KiWakeQueue(Thread->Queue);
@@ -1418,12 +1440,19 @@ KeTerminateThread(IN KPRIORITY Increment)
 
     /* Signal the thread */
     Thread->DispatcherHeader.SignalState = TRUE;
-    if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) {
-
+    if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE)
+    {
         /* Satisfy waits */
         KiWaitTest((PVOID)Thread, Increment);
     }
 
+    /* Remove the thread from the list */
+    RemoveEntryList(&Thread->ThreadListEntry);
+
+    /* Set us as terminated, decrease the Process's stack count */
+    Thread->State = Terminated;
+    Process->StackCount--;
+
     /* Find a new Thread */
     KiDispatchThreadNoLock(Terminated);
 }
index 8631d2f..e136051 100644 (file)
@@ -145,7 +145,8 @@ KeInitializeProcess(PKPROCESS Process,
 ULONG
 NTAPI
 KeSetProcess(PKPROCESS Process,
-             KPRIORITY Increment)
+             KPRIORITY Increment,
+             BOOLEAN InWait)
 {
     KIRQL OldIrql;
     ULONG OldState;
index 0051645..b74f501 100644 (file)
 
 /* FUNCTIONS *****************************************************************/
 
+VOID
+NTAPI
+LpcExitThread(IN PETHREAD Thread)
+{
+    /* Make sure that the Reply Chain is empty */
+    if (!IsListEmpty(&Thread->LpcReplyChain))
+    {
+        /* It's not, remove the entry */
+        RemoveEntryList(&Thread->LpcReplyChain);
+    }
+
+    /* Set the thread in exit mode */
+    Thread->LpcExitThreadCalled = TRUE;
+    Thread->LpcReplyMessageId = 0;
+
+    /* FIXME: Reply to the LpcReplyMessage */
+}
+
 /**********************************************************************
  * NAME
  *
index 8725e56..e5641da 100644 (file)
 #define NDEBUG
 #include <internal/debug.h>
 
-
-/**********************************************************************
- * NAME
- *     LpcSendTerminationPort/2
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-NTSTATUS STDCALL
-LpcSendTerminationPort (IN PEPORT Port,
-                       IN LARGE_INTEGER CreateTime)
-{
-  NTSTATUS Status;
-  CLIENT_DIED_MSG Msg;
-
-#ifdef __USE_NT_LPC__
-  Msg.h.u2.s2.Type = LPC_CLIENT_DIED;
-#endif
-  Msg.h.u1.s1.TotalLength = sizeof(Msg);
-  Msg.h.u1.s1.DataLength = sizeof(Msg) - sizeof(PORT_MESSAGE);
-  Msg.CreateTime = CreateTime;
-  Status = LpcRequestPort (Port, &Msg.h);
-  return(Status);
-}
-
-
 /**********************************************************************
  * NAME
  *     LpcSendDebugMessagePort/3
index 1cec79d..9d9e342 100644 (file)
@@ -22,66 +22,12 @@ ULONG MmUserProbeAddress = 0;
 PVOID MmHighestUserAddress = NULL;
 PBOOLEAN Mm64BitPhysicalAddress = FALSE;
 PVOID MmSystemRangeStart = NULL;
+ULONG MmReadClusterSize;
 
 MM_STATS MmStats;
 
 /* FUNCTIONS ****************************************************************/
 
-
-NTSTATUS 
-NTAPI
-MmReleaseMmInfo(PEPROCESS Process)
-{
-   PVOID Address;
-   PMEMORY_AREA MemoryArea;
-
-   DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process,
-          Process->ImageFileName);
-
-   MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
-
-   while ((MemoryArea = ((PMADDRESS_SPACE)&Process->VadRoot)->MemoryAreaRoot) != NULL)
-   {
-      switch (MemoryArea->Type)
-      {
-         case MEMORY_AREA_SECTION_VIEW:
-             Address = (PVOID)MemoryArea->StartingAddress;
-             MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
-             MmUnmapViewOfSection((PEPROCESS)Process, Address);
-             MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
-             break;
-
-         case MEMORY_AREA_VIRTUAL_MEMORY:
-         case MEMORY_AREA_PEB_OR_TEB:
-             MmFreeVirtualMemory(Process, MemoryArea);
-             break;
-
-         case MEMORY_AREA_SHARED_DATA:
-         case MEMORY_AREA_NO_ACCESS:
-             MmFreeMemoryArea((PMADDRESS_SPACE)&Process->VadRoot,
-                              MemoryArea,
-                              NULL,
-                              NULL);
-             break;
-
-         case MEMORY_AREA_MDL_MAPPING:
-            KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES);
-            break;
-
-         default:
-            KEBUGCHECK(0);
-      }
-   }
-
-   Mmi386ReleaseMmInfo(Process);
-
-   MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
-   MmDestroyAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
-
-   DPRINT("Finished MmReleaseMmInfo()\n");
-   return(STATUS_SUCCESS);
-}
-
 /*
  * @implemented
  */
index c88c45d..7b54aa9 100644 (file)
@@ -23,6 +23,33 @@ extern ULONG NtGlobalFlag;
 
 /* FUNCTIONS *****************************************************************/
 
+LCID
+NTAPI
+MmGetSessionLocaleId(VOID)
+{
+    PEPROCESS Process;
+    PAGED_CODE();
+
+    /* Get the current process */
+    Process = PsGetCurrentProcess();
+
+    /* Check if it's the Session Leader */
+    if (Process->Vm.Flags.SessionLeader)
+    {
+        /* Make sure it has a valid Session */
+        if (Process->Session)
+        {
+            /* Get the Locale ID */
+#if ROS_HAS_SESSIONS
+            return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
+#endif
+        }
+    }
+
+    /* Not a session leader, return the default */
+    return PsDefaultThreadLocaleId;
+}
+
 PVOID
 STDCALL
 MiCreatePebOrTeb(PEPROCESS Process,
@@ -489,6 +516,9 @@ MmCreateProcessAddressSpace(IN PEPROCESS Process,
         goto exit;
      }
 
+    /* The process now has an address space */
+    Process->HasAddressSpace = TRUE;
+
     /* Check if there's a Section Object */
     if (Section)
     {
@@ -559,3 +589,64 @@ exit:
     /* Return status to caller */
     return Status;
 }
+
+VOID
+NTAPI
+MmCleanProcessAddressSpace(IN PEPROCESS Process)
+{
+    /* FIXME: Add part of MmDeleteProcessAddressSpace here */
+}
+
+NTSTATUS 
+NTAPI
+MmDeleteProcessAddressSpace(PEPROCESS Process)
+{
+   PVOID Address;
+   PMEMORY_AREA MemoryArea;
+
+   DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
+          Process->ImageFileName);
+
+   MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
+
+   while ((MemoryArea = ((PMADDRESS_SPACE)&Process->VadRoot)->MemoryAreaRoot) != NULL)
+   {
+      switch (MemoryArea->Type)
+      {
+         case MEMORY_AREA_SECTION_VIEW:
+             Address = (PVOID)MemoryArea->StartingAddress;
+             MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
+             MmUnmapViewOfSection(Process, Address);
+             MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
+             break;
+
+         case MEMORY_AREA_VIRTUAL_MEMORY:
+         case MEMORY_AREA_PEB_OR_TEB:
+             MmFreeVirtualMemory(Process, MemoryArea);
+             break;
+
+         case MEMORY_AREA_SHARED_DATA:
+         case MEMORY_AREA_NO_ACCESS:
+             MmFreeMemoryArea((PMADDRESS_SPACE)&Process->VadRoot,
+                              MemoryArea,
+                              NULL,
+                              NULL);
+             break;
+
+         case MEMORY_AREA_MDL_MAPPING:
+            KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES);
+            break;
+
+         default:
+            KEBUGCHECK(0);
+      }
+   }
+
+   Mmi386ReleaseMmInfo(Process);
+
+   MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
+   MmDestroyAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
+
+   DPRINT("Finished MmReleaseMmInfo()\n");
+   return(STATUS_SUCCESS);
+}
index 12987c7..f107922 100644 (file)
@@ -979,6 +979,14 @@ Language=English
 SPIN_LOCK_INIT_FAILURE
 .
 
+MessageId=0x94
+Severity=Success
+Facility=System
+SymbolicName=KERNEL_STACK_LOCKED_AT_EXIT
+Language=English
+KERNEL_STACK_LOCKED_AT_EXIT
+.
+
 MessageId=0x96
 Severity=Success
 Facility=System
@@ -1085,6 +1093,23 @@ Language=English
  certain\n conditions. There is absolutely no warranty for ReactOS.\n
 .
 
+MessageId=0xE9
+Severity=Success
+Facility=System
+SymbolicName=ACTIVE_EX_WORKER_THREAD_TERMINATION
+Language=English
+ACTIVE_EX_WORKER_THREAD_TERMINATION
+.
+
+MessageId=0xEF
+Severity=Success
+Facility=System
+SymbolicName=CRITICAL_PROCESS_DIED
+Language=English
+CRITICAL_PROCESS_DIED
+.
+
+
 MessageId=0xFC
 Severity=Success
 Facility=System
index ce4adff..c7088db 100644 (file)
@@ -244,7 +244,7 @@ ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable,
         //
         // WE DONT CLOSE REGISTRY HANDLES BECAUSE CM IS BRAINDEAD
         //
-        DPRINT1("NOT CLOSING THE KEY\n");
+        DPRINT("NOT CLOSING THE KEY\n");
     }
     else
     {
@@ -1119,6 +1119,13 @@ ObpDuplicateHandleCallback(IN PHANDLE_TABLE HandleTable,
     return Ret;
 }
 
+VOID
+NTAPI
+ObClearProcessHandleTable(IN PEPROCESS Process)
+{
+    /* FIXME */
+}
+
 /*++
 * @name ObpCreateHandleTable
 *
index a670238..6ab6861 100644 (file)
@@ -11,6 +11,7 @@
 
 /* INCLUDES ******************************************************************/
 
+#define NTDDI_VERSION NTDDI_WINXP
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
@@ -20,6 +21,49 @@ POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL;
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
+VOID
+NTAPI
+ObDereferenceDeviceMap(IN PEPROCESS Process)
+{
+    //KIRQL OldIrql;
+    PDEVICE_MAP DeviceMap = Process->DeviceMap;
+
+    /* FIXME: We don't use Process Devicemaps yet */
+    if (DeviceMap)
+    {
+        /* FIXME: Acquire the DeviceMap Spinlock */
+        // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
+
+        /* Delete the device map link and dereference it */
+        Process->DeviceMap = NULL;
+        if (--DeviceMap->ReferenceCount)
+        {
+            /* Nobody is referencing it anymore, unlink the DOS directory */
+            DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
+
+            /* FIXME: Release the DeviceMap Spinlock */
+            // KeReleasepinLock(DeviceMap->Lock, OldIrql);
+
+            /* Dereference the DOS Devices Directory and free the Device Map */
+            ObDereferenceObject(DeviceMap->DosDevicesDirectory);
+            ExFreePool(DeviceMap);
+        }
+        else
+        {
+            /* FIXME: Release the DeviceMap Spinlock */
+            // KeReleasepinLock(DeviceMap->Lock, OldIrql);
+        }
+    }
+}
+
+VOID
+NTAPI
+ObInheritDeviceMap(IN PEPROCESS Parent,
+                   IN PEPROCESS Process)
+{
+    /* FIXME: Devicemap Support */
+}
+
 /*++
 * @name ObpDeleteNameCheck
 *
index 7d61b22..b09affd 100644 (file)
@@ -90,7 +90,7 @@ ObfDereferenceObject(IN PVOID Object)
 
     if (Header->PointerCount < Header->HandleCount)
     {
-        DPRINT1("Misbehaving object: %wZ\n", &Header->Type->Name);
+        DPRINT("Misbehaving object: %wZ\n", &Header->Type->Name);
         return;
     }
 
@@ -100,7 +100,7 @@ ObfDereferenceObject(IN PVOID Object)
         /* Sanity check */
         if (Header->HandleCount)
         {
-            DPRINT1("Misbehaving object: %wZ\n", &Header->Type->Name);
+            DPRINT("Misbehaving object: %wZ\n", &Header->Type->Name);
             return;
         }
 
index 18aef5d..a5babbe 100644 (file)
@@ -183,6 +183,13 @@ PoSetDeviceBusy(
 {
 }
 
+VOID
+NTAPI
+PopCleanupPowerState(IN PPOWER_STATE PowerState)
+{
+    /* FIXME */
+}
+
 /*
  * @unimplemented
  */
index 9c59db7..fe53a04 100644 (file)
@@ -4,16 +4,14 @@
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ps/job.c
  * PURPOSE:         Job Native Functions
- *
  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net) (stubs)
  *                  Thomas Weidenmueller <w3seek@reactos.com>
  */
 
-/* Note: Jobs are only supported on Win2K+ */
 /* INCLUDES *****************************************************************/
 
-#define NDEBUG
 #include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
 #if defined (ALLOC_PRAGMA)
@@ -39,7 +37,8 @@ static GENERIC_MAPPING PiJobMapping =
 
 /* FUNCTIONS *****************************************************************/
 
-VOID STDCALL
+VOID
+NTAPI
 PiDeleteJob ( PVOID ObjectBody )
 {
     PEJOB Job = (PEJOB)ObjectBody;
@@ -89,8 +88,7 @@ PsInitJobManagment ( VOID )
 
 NTSTATUS
 NTAPI
-PspAssignProcessToJob (
-    PEPROCESS Process,
+PspAssignProcessToJob(PEPROCESS Process,
     PEJOB Job)
 {
     DPRINT("PspAssignProcessToJob() is unimplemented!\n");
@@ -99,8 +97,7 @@ PspAssignProcessToJob (
 
 NTSTATUS
 NTAPI
-PspTerminateJobObject (
-    PEJOB Job,
+PspTerminateJobObject(PEJOB Job,
     KPROCESSOR_MODE AccessMode,
     NTSTATUS ExitStatus )
 {
@@ -108,6 +105,21 @@ PspTerminateJobObject (
     return STATUS_NOT_IMPLEMENTED;
 }
 
+VOID
+NTAPI
+PspRemoveProcessFromJob(IN PEPROCESS Process,
+                        IN PEJOB Job)
+{
+    /* FIXME */
+}
+
+VOID
+NTAPI
+PspExitProcessFromJob(IN PEJOB Job,
+                      IN PEPROCESS Process)
+{
+    /* FIXME */
+}
 
 /*
  * @unimplemented
@@ -547,8 +559,7 @@ PsGetJobUIRestrictionsClass ( PEJOB Job )
  */
 VOID
 STDCALL
-PsSetJobUIRestrictionsClass (
-    PEJOB Job,
+PsSetJobUIRestrictionsClass(PEJOB Job,
     ULONG UIRestrictionsClass)
 {
     ASSERT(Job);
index 518b78b..58c0828 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * 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/kill.c
- * PURPOSE:         Thread Termination and Reaping
- *
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
- *                  David Welch (welch@cwcom.net)
+ * PURPOSE:         Process Manager: Process and Thread Termination
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Filip Navara (xnavara@reactos.org)
+ *                  Thomas Weidenmueller (w3seek@reactos.org
  */
 
 /* INCLUDES *****************************************************************/
 
 /* GLOBALS *******************************************************************/
 
-PETHREAD PspReaperList = NULL;
+LIST_ENTRY PspReaperListHead = {0};
 WORK_QUEUE_ITEM PspReaperWorkItem;
-BOOLEAN PspReaping = FALSE;
 extern LIST_ENTRY PsActiveProcessHead;
 extern FAST_MUTEX PspActiveProcessMutex;
 extern PHANDLE_TABLE PspCidTable;
+extern PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout;
+extern PKWIN32_THREAD_CALLOUT PspW32ThreadCallout;
+extern PEPROCESS PsInitialSystemProcess;
+extern PEPROCESS PsIdleProcess;
 
 /* FUNCTIONS *****************************************************************/
 
-VOID
-STDCALL
-PspReapRoutine(PVOID Context)
+NTSTATUS
+NTAPI
+PspTerminateProcess(IN PEPROCESS Process,
+                    IN NTSTATUS ExitStatus)
 {
-    KIRQL OldIrql;
-    PETHREAD Thread, NewThread;
-
-    /* Acquire lock */
-    DPRINT("Evil reaper running!!\n");
-    OldIrql = KeAcquireDispatcherDatabaseLock();
-
-    /* Get the first Thread Entry */
-    Thread = PspReaperList;
-    PspReaperList = NULL;
-    DPRINT("PspReaperList: %x\n", Thread);
-
-    /* Check to see if the list is empty */
-    do {
-
-        /* Unlock the Dispatcher */
-        KeReleaseDispatcherDatabaseLock(OldIrql);
-
-        /* Is there a thread on the list? */
-        while (Thread) {
+    PAGED_CODE();
+    PETHREAD Thread = NULL;
 
-            /* Get the next Thread */
-            DPRINT("Thread: %x\n", Thread);
-            DPRINT("Thread: %x\n", Thread->ReaperLink);
-            NewThread = Thread->ReaperLink;
+    /* Check if this is a Critical Process, and Bugcheck */
+    if (Process->BreakOnTermination)
+    {
+        /* FIXME: Add critical Process support */
+        DPRINT1("A critical Process is being terminated\n");
+        KEBUGCHECK(0);
+    }
 
-            /* Remove reference to current thread */
-            ObDereferenceObject(Thread);
+    /* Set the delete flag */
+    InterlockedOr(&Process->Flags, 8);
 
-            /* Move to next Thread */
-            Thread = NewThread;
+    /* Get the first thread */
+    while ((Thread = PsGetNextProcessThread(Process, Thread)))
+    {
+        /* Kill it */
+        PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
         }
 
-        /* No more linked threads... Reacquire the Lock */
-        OldIrql = KeAcquireDispatcherDatabaseLock();
-
-        /* Now try to get a new thread from the list */
-        Thread = PspReaperList;
-        PspReaperList = NULL;
-        DPRINT("PspReaperList: %x\n", Thread);
+    /* Clear the handle table */
+    ObClearProcessHandleTable(Process);
 
-        /* Loop again if there is a new thread */
-    } while (Thread);
-
-    PspReaping = FALSE;
-    DPRINT("Done reaping\n");
-    KeReleaseDispatcherDatabaseLock(OldIrql);
+    /* Return success*/
+    return STATUS_SUCCESS;
 }
 
 VOID
-STDCALL
-PspKillMostProcesses(VOID)
+NTAPI
+PspShutdownProcessManager(VOID)
 {
-    PLIST_ENTRY current_entry;
-    PEPROCESS current;
-
-    ASSERT(PsGetCurrentProcessId() == PsInitialSystemProcess->UniqueProcessId);
+    PEPROCESS Process = NULL;
 
-    /* Acquire the Active Process Lock */
-    ExAcquireFastMutex(&PspActiveProcessMutex);
-
-    /* Loop all processes on the list */
-    current_entry = PsActiveProcessHead.Flink;
-    while (current_entry != &PsActiveProcessHead)
+    /* Loop every process */
+    while ((Process == PsGetNextProcess(Process)))
     {
-        current = CONTAINING_RECORD(current_entry, EPROCESS, ActiveProcessLinks);
-        current_entry = current_entry->Flink;
-
-        if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId)
+        /* Make sure this isn't the idle or initial process */
+        if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess))
         {
-            /* Terminate all the Threads in this Process */
-            PspTerminateProcessThreads(current, STATUS_SUCCESS);
+            /* Kill it */
+            PspTerminateProcess(Process, STATUS_SYSTEM_SHUTDOWN);
         }
     }
+}
 
-    /* Release the lock */
-    ExReleaseFastMutex(&PspActiveProcessMutex);
+VOID
+NTAPI
+PspExitApcRundown(IN PKAPC Apc)
+{
+    PAGED_CODE();
+
+    /* Free the APC */
+    ExFreePool(Apc);
 }
 
 VOID
-STDCALL
-PspTerminateProcessThreads(PEPROCESS Process,
-                           NTSTATUS ExitStatus)
+NTAPI
+PspReapRoutine(PVOID Context)
 {
-    PLIST_ENTRY CurrentEntry;
-    PETHREAD Thread, CurrentThread = PsGetCurrentThread();
+    PLIST_ENTRY *ListAddr;
+    PLIST_ENTRY NextEntry;
+    PETHREAD Thread;
 
-    CurrentEntry = Process->ThreadListHead.Flink;
-    while (CurrentEntry != &Process->ThreadListHead) {
+    /* Get the Reaper Address Pointer */
+    ListAddr = &PspReaperListHead.Flink;
 
-        /* Get the Current Thread */
-        Thread = CONTAINING_RECORD(CurrentEntry, ETHREAD, ThreadListEntry);
+    /* Start main loop */
+    do
+    {
+        /* Write magic value and return the next entry to process */
+        NextEntry = InterlockedExchangePointer(ListAddr, (PVOID)1);
+        ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1));
 
-        /* Move to the Next Thread */
-        CurrentEntry = CurrentEntry->Flink;
+        /* Start inner loop */
+        do
+        {
+            /* Get the first Thread Entry */
+            Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink);
 
-        /* Make sure it's not the one we're in */
-        if (Thread != CurrentThread) {
+            /* Delete this entry's kernel stack */
+            MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit,
+                                Thread->Tcb.LargeStack);
+            Thread->Tcb.InitialStack = NULL;
 
-            /* Make sure it didn't already terminate */
-            if (!Thread->Terminated) {
+            /* Move to the next entry */
+            NextEntry = NextEntry->Flink;
 
-                Thread->Terminated = TRUE;
+            /* Dereference this thread */
+            ObDereferenceObject(Thread);
+        } while ((NextEntry != NULL) && (NextEntry != (PVOID)1));
 
-                /* Terminate it by APC */
-                PspTerminateThreadByPointer(Thread, ExitStatus);
-            }
-        }
-    }
+        /* Remove magic value, keep looping if it got changed */
+    } while (InterlockedCompareExchangePointer(ListAddr, 0, 1) != (PVOID)1);
 }
 
 VOID
-STDCALL
+NTAPI
 PspDeleteProcess(PVOID ObjectBody)
 {
     PEPROCESS Process = (PEPROCESS)ObjectBody;
+    KAPC_STATE ApcState;
+    DPRINT1("PspDeleteProcess(ObjectBody %x)\n", ObjectBody);
+    PAGED_CODE();
+    DPRINT1("Name: %.16s\n", &Process->ImageFileName);
 
-    DPRINT("PiDeleteProcess(ObjectBody %x)\n", ObjectBody);
-
+    /* Check if it has an Active Process Link */
+    if (Process->ActiveProcessLinks.Flink)
+    {
     /* Remove it from the Active List */
     ExAcquireFastMutex(&PspActiveProcessMutex);
     RemoveEntryList(&Process->ActiveProcessLinks);
     ExReleaseFastMutex(&PspActiveProcessMutex);
+    }
 
-    /* Delete the CID Handle */
-    if(Process->UniqueProcessId)
+    /* Check for Auditing information */
+    if (Process->SeAuditProcessCreationInfo.ImageFileName)
+    {
+        /* Free it */
+        ExFreePool(Process->SeAuditProcessCreationInfo.ImageFileName);
+        Process->SeAuditProcessCreationInfo.ImageFileName = NULL;
+    }
+
+    /* Check if we have a job */
+    if (Process->Job)
+    {
+        /* Remove the process from the job */
+        PspRemoveProcessFromJob(Process, Process->Job);
+
+        /* Dereference it */
+        ObDereferenceObject(Process->Job);
+        Process->Job = NULL;
+    }
+
+    /* Increase the stack count */
+    Process->Pcb.StackCount++;
+
+    /* Check if we have a debug port */
+    if (Process->DebugPort)
     {
-        ExDestroyHandle(PspCidTable, Process->UniqueProcessId);
+        /* Dererence the Debug Port */
+        ObDereferenceObject(Process->DebugPort);
+        Process->DebugPort = NULL;
     }
 
-    /* Delete the process lock */
-    ExFreePool(Process->LockEvent);
+    /* Check if we have an exception port */
+    if (Process->ExceptionPort)
+    {
+        /* Dererence the Exception Port */
+        ObDereferenceObject(Process->ExceptionPort);
+        Process->ExceptionPort = NULL;
+    }
+
+    /* Check if we have a section object */
+    if (Process->SectionObject)
+    {
+        /* Dererence the Section Object */
+        ObDereferenceObject(Process->SectionObject);
+        Process->SectionObject = NULL;
+    }
+
+    /* Clean LDT and VDM_OBJECTS */
+    PspDeleteLdt(Process);
+    PspDeleteVdmObjects(Process);
+
+    /* Delete the Object Table */
+    if (Process->ObjectTable)
+    {
+        /* Attach to the process */
+        KeStackAttachProcess(&Process->Pcb, &ApcState);
+
+        /* Kill the Object Info */
+        ObKillProcess(Process);
+
+        /* Dettach */
+        KeUnstackDetachProcess(&ApcState);
+    }
 
     /* KDB hook */
     KDB_DELETEPROCESS_HOOK(Process);
 
-    /* Dereference the Token */
-    SeDeassignPrimaryToken(Process);
+    /* Check if we have an address space, and clean it */
+    if (Process->HasAddressSpace)
+    {
+        /* Attach to the process */
+        KeStackAttachProcess(&Process->Pcb, &ApcState);
+
+        /* Clean the Address Space */
+        PspExitProcess(FALSE, Process);
+
+        /* Dettach */
+        KeUnstackDetachProcess(&ApcState);
+
+        /* Completely delete the Address Space */
+        MmDeleteProcessAddressSpace(Process);
+}
+
+    /* See if we have a PID */
+    if(Process->UniqueProcessId)
+    {
+        /* Delete the PID */
+        if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId)))
+        {
+            /* Something wrong happened, bugcheck */
+            KEBUGCHECK(CID_HANDLE_DELETION);
+        }
+    }
+
+    /* Cleanup security information */
+    PspDeleteProcessSecurity(Process);
+
+    /* Check if we have kept information on the Working Set */
+    if (Process->WorkingSetWatch)
+    {
+        /* Free it */
+        ExFreePool(Process->WorkingSetWatch);
+
+        /* And return the quota it was taking up */
+        PsReturnProcessNonPagedPoolQuota(Process, 0x2000);
+    }
 
-    /* Release Memory Information */
-    MmReleaseMmInfo(Process);
+    /* Dereference the Device Map */
+    ObDereferenceDeviceMap(Process);
 
-    /* Delete the W32PROCESS structure if there's one associated */
-    if(Process->Win32Process != NULL) ExFreePool(Process->Win32Process);
+    /* Destroy the Quota Block */
+    PspDestroyQuotaBlock(Process);
 }
 
 VOID
-STDCALL
+NTAPI
 PspDeleteThread(PVOID ObjectBody)
 {
     PETHREAD Thread = (PETHREAD)ObjectBody;
     PEPROCESS Process = Thread->ThreadsProcess;
+    DPRINT1("PspDeleteThread(Thread %p, Process %p)\n", ObjectBody, Process);
+    PAGED_CODE();
+    //ASSERT(Thread->Tcb.Win32Thread == NULL); FIXME
 
-    DPRINT("PiDeleteThread(ObjectBody 0x%x, process 0x%x)\n",ObjectBody, Thread->ThreadsProcess);
-
-    /* Deassociate the Process */
-    Thread->ThreadsProcess = NULL;
+    /* Check if we have a stack */
+    if (Thread->Tcb.InitialStack)
+    {
+        /* Release it */
+        MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit,
+                            Thread->Tcb.LargeStack);
+    }
 
     /* Delete the CID Handle */
     if(Thread->Cid.UniqueThread)
     {
-        ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread);
+        if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread)))
+        {
+            /* Something wrong happened, bugcheck */
+            KEBUGCHECK(CID_HANDLE_DELETION);
+        }
     }
 
-    /* Free the W32THREAD structure if present */
-    if(Thread->Tcb.Win32Thread != NULL) ExFreePool (Thread->Tcb.Win32Thread);
+    /* Cleanup impersionation information */
+    PspDeleteThreadSecurity(Thread);
+
+    /* Make sure the thread was inserted, before continuing */
+    if (!Process) return;
 
-    /* Release the Kernel Stack */
-    MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, Thread->Tcb.LargeStack);
+    /* Check if the thread list is valid */
+    if (Thread->ThreadListEntry.Flink)
+    {
+        /* Lock the thread's process */
+        PsLockProcess(Process, FALSE);
+
+        /* Remove us from the list */
+        RemoveEntryList(&Thread->ThreadListEntry);
+
+        /* Release the lock */
+        PsUnlockProcess(Process);
+    }
 
     /* Dereference the Process */
     ObDereferenceObject(Process);
@@ -213,143 +322,364 @@ PspDeleteThread(PVOID ObjectBody)
  * See "Windows Internals" - Chapter 13, Page 50-53
  */
 VOID
-STDCALL
+NTAPI
 PspExitThread(NTSTATUS ExitStatus)
 {
-    PETHREAD CurrentThread;
-    BOOLEAN Last;
-    PEPROCESS CurrentProcess;
-    PTERMINATION_PORT TerminationPort;
+    CLIENT_DIED_MSG TerminationMsg;
+    NTSTATUS Status;
     PTEB Teb;
-    KIRQL oldIrql;
+    PEPROCESS CurrentProcess;
+    PETHREAD Thread;
+    PVOID DeallocationStack;
+    ULONG Dummy;
+    BOOLEAN Last = FALSE;
+    PTERMINATION_PORT TerminationPort, NextPort;
     PLIST_ENTRY FirstEntry, CurrentEntry;
     PKAPC Apc;
-
-    DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
+    PTOKEN PrimaryToken;
+    PAGED_CODE();
+    DPRINT1("PspExitThread(%p, %lx)\n", PsGetCurrentThread(), ExitStatus);
 
     /* Get the Current Thread and Process */
-    CurrentThread = PsGetCurrentThread();
-    CurrentProcess = CurrentThread->ThreadsProcess;
-
-    /* Set the Exit Status and Exit Time */
-    CurrentThread->ExitStatus = ExitStatus;
-    KeQuerySystemTime(&CurrentThread->ExitTime);
+    Thread = PsGetCurrentThread();
+    CurrentProcess = Thread->ThreadsProcess;
+    ASSERT((Thread) == PsGetCurrentThread());
 
     /* Can't terminate a thread if it attached another process */
-    if (KeIsAttachedProcess()) {
-
-        KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG) CurrentProcess,
-                     (ULONG) CurrentThread->Tcb.ApcState.Process,
-                     (ULONG) CurrentThread->Tcb.ApcStateIndex,
-                     (ULONG) CurrentThread);
+    if (KeIsAttachedProcess())
+    {
+        KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
+                     (ULONG)CurrentProcess,
+                     (ULONG)Thread->Tcb.ApcState.Process,
+                     (ULONG)Thread->Tcb.ApcStateIndex,
+                     (ULONG)Thread);
     }
 
     /* Lower to Passive Level */
-    KeLowerIrql(PASSIVE_LEVEL);
+    KfLowerIrql(PASSIVE_LEVEL);
+
+    /* Can't be a worker thread */
+    if (Thread->ActiveExWorker)
+    {
+        KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION,
+                     (ULONG)Thread,
+                     0,
+                     0,
+                     0);
+    }
+
+    /* Can't have pending APCs */
+    if (Thread->Tcb.CombinedApcDisable != 0)
+    {
+        KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
+                     0,
+                     Thread->Tcb.KernelApcDisable,
+                     APC_LEVEL,
+                     0);
+    }
+
+    /* FIXME: Lock the thread
+     * ExAcquireRundownProtect(&Thread->RundownProtect);
+     */
+
+    /* Cleanup the power state */
+    PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState);
+
+    /* Call the WMI Callback for Threads */
+    //WmiTraceThread(Thread, NULL, FALSE);
+
+    /* Run Thread Notify Routines before we desintegrate the thread */
+    PspRunCreateThreadNotifyRoutines(Thread, FALSE);
 
     /* Lock the Process before we modify its thread entries */
     PsLockProcess(CurrentProcess, FALSE);
 
-    /* wake up the thread so we don't deadlock on PsLockProcess */
-    KeForceResumeThread(&CurrentThread->Tcb);
+    /* Wake up the thread so we don't deadlock on PsLockProcess */
+    KeForceResumeThread(&Thread->Tcb);
 
-    /* Run Thread Notify Routines before we desintegrate the thread */
-    PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
+    /* Decrease the active thread count, and check if it's 0 */
+    if (!(--CurrentProcess->ActiveThreads))
+    {
+        /* Set the delete flag */
+        InterlockedOr(&CurrentProcess->Flags, 8);
 
-    /* Remove the thread from the thread list of its process */
-    RemoveEntryList(&CurrentThread->ThreadListEntry);
-    Last = IsListEmpty(&CurrentProcess->ThreadListHead);
+        /* Remember we are last */
+        Last = TRUE;
 
-    /* Set the last Thread Exit Status */
+        /* Check if this termination is due to the thread dying */
+        if (ExitStatus == STATUS_THREAD_IS_TERMINATING)
+        {
+            /* Check if the last thread was pending */
+            if (CurrentProcess->ExitStatus == STATUS_PENDING)
+            {
+                /* Use the last exit status */
+                CurrentProcess->ExitStatus = CurrentProcess->LastThreadExitStatus;
+            }
+        }
+        else
+        {
+            /* Just a normal exit, write the code */
+            CurrentProcess->ExitStatus = ExitStatus;
+        }
+
+        /* FIXME: Wait on the other threads to finish */
+    }
+    else if (ExitStatus != STATUS_THREAD_IS_TERMINATING)
+    {
+        /* Write down the exit status of the last thread to get killed */
     CurrentProcess->LastThreadExitStatus = ExitStatus;
+    }
 
-    if (Last) {
+    /* Unlock the Process */
+    PsUnlockProcess(CurrentProcess);
 
-       /* 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;
-       CurrentProcess->ExitStatus = ExitStatus;
+    /* Check if the process has a debug port and if this is a user thread */
+    if ((CurrentProcess->DebugPort) && 
+        !(Thread->SystemThread))
+    {
+        /* Notify the Debug API. */
+        Last ? DbgkExitProcess(CurrentProcess->ExitStatus) :
+               DbgkExitThread(ExitStatus);
     }
 
-    /* Check if the process has a debug port */
-    if (CurrentProcess->DebugPort) {
+    /* Check if this is a Critical Thread */
+    if ((KdDebuggerEnabled) && (Thread->BreakOnTermination))
+    {
+        /* FIXME: Add critical thread support */
+        KEBUGCHECK(0);
+    }
 
-        /* Notify the Debug API. TODO */
-        //Last ? DbgkExitProcess(ExitStatus) : DbgkExitThread(ExitStatus);
+    /* Check if it's the last thread and this is a Critical Process */
+    if ((Last) && (CurrentProcess->BreakOnTermination))
+    {
+        /* Check if a debugger is here to handle this */
+        if (KdDebuggerEnabled)
+        {
+            /* FIXME: Add critical process support */
+            DbgBreakPoint();
     }
+        else
+        {
+            /* Bugcheck, we can't allow this */
+            KEBUGCHECKEX(CRITICAL_PROCESS_DIED,
+                         (ULONG_PTR)CurrentProcess,
+                         0,
+                         0,
+                         0);
+        }
+    }
+
+    /* Sanity check */
+    ASSERT(Thread->Tcb.CombinedApcDisable == 0);
 
     /* Process the Termination Ports */
-    while ((TerminationPort = CurrentThread->TerminationPort)) {
+    TerminationPort = Thread->TerminationPort;
+    if (TerminationPort)
+    {
+        /* Setup the message header */
+        TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
+        TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
+        TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
+                                            sizeof(PORT_MESSAGE);
+
+        /* Loop each port */
+        do
+        {
+            /* Save the Create Time */
+            TerminationMsg.CreateTime = Thread->CreateTime;
+
+TryAgain:
+            /* Send the LPC Message */
+            Status = LpcRequestPort(TerminationPort->Port, &TerminationMsg.h);
+            if ((Status == STATUS_NO_MEMORY) ||
+                (Status == STATUS_INSUFFICIENT_RESOURCES))
+            {
+                /* Wait a bit and try again */
+                KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
+                goto TryAgain;
+            }
 
-        DPRINT("TerminationPort: %p\n", TerminationPort);
+            /* Dereference this LPC Port */
+            ObDereferenceObject(TerminationPort->Port);
 
-        /* Get the next one */
-        CurrentThread->TerminationPort = TerminationPort->Next;
+            /* Move to the next one */
+            NextPort = TerminationPort->Next;
 
-        /* Send the LPC Message */
-        LpcSendTerminationPort(TerminationPort->Port, CurrentThread->CreateTime);
-        ObDereferenceObject(TerminationPort->Port);
+            /* Free the Termination Port Object */
+            ExFreePool(TerminationPort);
 
-        /* Free the Port */
-        ExFreePool(TerminationPort);
+            /* Keep looping as long as there is a port */
+        } while ((TerminationPort = NextPort));
+    }
+    else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) &&
+              (Thread->DeadThread)) ||
+             !(Thread->DeadThread))
+    {
+        /*
+         * This case is special and deserves some extra comments. What
+         * basically happens here is that this thread doesn't have a termination
+         * port, which means that it died before being fully created. Since we
+         * still have to notify an LPC Server, we'll use the exception port,
+         * which we know exists. However, we need to know how far the thread
+         * actually got created. We have three possibilites:
+         *
+         *  - NtCreateThread returned an error really early: DeadThread is set.
+         *  - NtCreateThread managed to create the thread: DeadThread is off.
+         *  - NtCreateThread was creating the thread (with Deadthread set,
+         *    but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING
+         *    is our exit code.)
+         *
+         * For the 2 & 3rd scenarios, the thread has been created far enough to
+         * warrant notification to the LPC Server.
+         */
+
+        /* Setup the message header */
+        TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
+        TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
+        TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
+                                            sizeof(PORT_MESSAGE);
+
+        /* Make sure the process has an exception port */
+        if (CurrentProcess->ExceptionPort)
+        {
+            /* Save the Create Time */
+            TerminationMsg.CreateTime = Thread->CreateTime;
+
+TryAgain2:
+            /* Send the LPC Message */
+            Status = LpcRequestPort(CurrentProcess->ExceptionPort,
+                                    &TerminationMsg.h);
+            if ((Status == STATUS_NO_MEMORY) ||
+                (Status == STATUS_INSUFFICIENT_RESOURCES))
+            {
+                /* Wait a bit and try again */
+                KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
+                goto TryAgain2;
+            }
+        }
     }
 
-    /* Rundown Win32 Structures */
-    PsTerminateWin32Thread(CurrentThread);
-    if (Last) PsTerminateWin32Process(CurrentProcess);
+    /* Rundown Win32 Thread if there is one */
+    if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread, FALSE);
 
-    /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */
-    //CmNotifyRunDown(CurrentThread);
+    /* If we are the last thread and have a W32 Process */
+    if ((Last) && (CurrentProcess->Win32Process))
+    {
+        /* Run it down too */
+        PspW32ProcessCallout(CurrentProcess, FALSE);
+    }
+
+    /* Make sure Stack Swap isn't enabled */
+    if (Thread->Tcb.EnableStackSwap)
+    {
+        /* Stack swap really shouldn't be on during exit !*/
+        KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0);
+    }
+
+    /* Cancel I/O for the thread. */
+    IoCancelThreadIo(Thread);
+
+    /* Rundown Timers */
+    ExTimerRundown();
+
+    /* FIXME: Rundown Registry Notifications (NtChangeNotify)
+    CmNotifyRunDown(Thread); */
+
+    /* Clear NPX Thread */
+    InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, NULL, Thread);
+
+    /* Rundown Mutexes */
+    KeRundownThread();
 
     /* Free the TEB */
-    if((Teb = CurrentThread->Tcb.Teb))
+    if((Teb = Thread->Tcb.Teb))
     {
-        /* Clean up the stack first, if requested */
-        if (Teb->FreeStackOnTermination)
+        /* Check if the thread isn't terminated and if we should free stack */
+        if (!(Thread->Terminated) && (Teb->FreeStackOnTermination))
         {
-            ULONG Dummy = 0;
+            /* Set the TEB's Deallocation Stack as the Base Address */
+            Dummy = 0;
+            DeallocationStack = Teb->DeallocationStack;
+
+            /* Free the Thread's Stack */
             ZwFreeVirtualMemory(NtCurrentProcess(),
-                                &Teb->DeallocationStack,
+                                &DeallocationStack,
                                 &Dummy,
                                 MEM_RELEASE);
         }
         
-        DPRINT("Decommit teb at %p\n", Teb);
+        /* Free the debug handle */
+        if (Teb->DbgSsReserved[2]) NtClose(Teb->DbgSsReserved[2]);
+        
+        /* Decommit the TEB */
         MmDeleteTeb(CurrentProcess, Teb);
-        CurrentThread->Tcb.Teb = NULL;
+        Thread->Tcb.Teb = NULL;
     }
 
-    /* The last Thread shuts down the Process */
-    if (Last) PspExitProcess(CurrentProcess);
+    /* Free LPC Data */
+    LpcExitThread(Thread);
 
-    /* Unlock the Process */
-    PsUnlockProcess(CurrentProcess);
+    /* Save the exit status and exit time */
+    Thread->ExitStatus = ExitStatus;
+    KeQuerySystemTime(&Thread->ExitTime);
 
-    /* Cancel I/O for the thread. */
-    IoCancelThreadIo(CurrentThread);
+    /* Sanity check */
+    ASSERT(Thread->Tcb.CombinedApcDisable == 0);
 
-    /* Rundown Timers */
-    ExTimerRundown();
-    KeCancelTimer(&CurrentThread->Tcb.Timer);
+    /* Check if this is the final thread or not */
+    if (Last)
+    {
+        /* Set the process exit time */
+        CurrentProcess->ExitTime = Thread->ExitTime;
 
-    /* If the Processor Control Block's NpxThread points to the current thread
-     * unset it.
-     */
-    KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
-    (void)InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread,
-                                            NULL,
-                                            (PVOID)CurrentThread);
-    KeLowerIrql(oldIrql);
+        /* Exit the process */
+        PspExitProcess(TRUE, CurrentProcess);
 
-    /* Rundown Mutexes */
-    KeRundownThread();
+        /* Get the process token and check if we need to audit */
+        PrimaryToken = PsReferencePrimaryToken(CurrentProcess);
+        if (SeDetailedAuditingWithToken(PrimaryToken))
+        {
+            /* Audit the exit */
+            SeAuditProcessExit(CurrentProcess);
+        }
+
+        /* Dereference the process token */
+        ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken);
 
-    /* Disable new APC Queuing, this is as far as we'll let them go */
-    KeDisableThreadApcQueueing(&CurrentThread->Tcb);
+        /* Check if this is a VDM Process and rundown the VDM DPCs if so */
+        if (CurrentProcess->VdmObjects);// VdmRundownDpcs(CurrentProcess);
+
+        /* Kill the process in the Object Manager */
+        ObKillProcess(CurrentProcess);
+
+        /* Check if we have a section object */
+        if (CurrentProcess->SectionObject)
+        {
+            /* Dereference and clear the Section Object */
+            ObDereferenceObject(CurrentProcess->SectionObject);
+            CurrentProcess->SectionObject = NULL;
+        }
+
+        /* Check if the process is part of a job */
+        if (CurrentProcess->Job)
+        {
+            /* Remove the process from the job */
+            PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess);
+        }
+    }
+
+    /* Disable APCs */
+    KeEnterCriticalRegion();
+
+    /* Disable APC queueing, force a resumption */
+    Thread->Tcb.ApcQueueable = FALSE;
+    KeForceResumeThread(&Thread->Tcb);
+
+    /* Re-enable APCs */
+    KeLeaveCriticalRegion();
 
     /* Flush the User APCs */
-    FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode);
+    FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode);
     if (FirstEntry != NULL)
     {
         CurrentEntry = FirstEntry;
@@ -376,269 +706,372 @@ PspExitThread(NTSTATUS ExitStatus)
         while (CurrentEntry != FirstEntry);
     }
 
+    /* Clean address space if this was the last thread */
+    if (Last) MmCleanProcessAddressSpace(CurrentProcess);
+
     /* Call the Lego routine */
-    if (CurrentThread->Tcb.LegoData) PspRunLegoRoutine(&CurrentThread->Tcb);
+    if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb);
 
     /* Flush the APC queue, which should be empty */
-    if ((FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode)))
+    if ((FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode)))
     {
         /* Bugcheck time */
         KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
                      (ULONG_PTR)FirstEntry,
-                     CurrentThread->Tcb.KernelApcDisable,
-                     oldIrql,
+                     Thread->Tcb.KernelApcDisable,
+                     KeGetCurrentIrql(),
                      0);
     }
 
+    /* Signal the process if this was the last thread */
+    if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE);
+
     /* Terminate the Thread from the Scheduler */
     KeTerminateThread(0);
-    DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
-    KEBUGCHECK(0);
 }
 
 VOID
-STDCALL
+NTAPI
 PsExitSpecialApc(PKAPC Apc,
                  PKNORMAL_ROUTINE* NormalRoutine,
                  PVOID* NormalContext,
                  PVOID* SystemArgument1,
                  PVOID* SystemArguemnt2)
 {
-    DPRINT("PsExitSpecialApc called: 0x%x (proc: 0x%x, '%.16s')\n", 
-           PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
+    NTSTATUS Status;
+    PAGED_CODE();
+    DPRINT1("PsExitSpecialApc: [%p:%p], '%.16s')\n", 
+            PsGetCurrentThread(),
+            PsGetCurrentProcess(),
+            PsGetCurrentProcess()->ImageFileName);
 
     /* Don't do anything unless we are in User-Mode */
     if (Apc->SystemArgument2)
     {
-        NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
-
         /* Free the APC */
-        ExFreePool(Apc);
+        Status = (NTSTATUS)Apc->NormalContext;
+        PspExitApcRundown(Apc);
 
         /* Terminate the Thread */
-        PspExitThread(ExitStatus);
-
-        /* we should never reach this point! */
-        KEBUGCHECK(0);
+        PspExitThread(Status);
     }
 }
 
 VOID
-STDCALL
+NTAPI
 PspExitNormalApc(PVOID NormalContext,
                  PVOID SystemArgument1,
                  PVOID SystemArgument2)
 {
     PKAPC Apc = (PKAPC)SystemArgument1;
     PETHREAD Thread = PsGetCurrentThread();
-    NTSTATUS ExitStatus;
-        
-    DPRINT("PspExitNormalApc called: 0x%x (proc: 0x%x, '%.16s')\n", 
-           PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
+    PAGED_CODE();
+    DPRINT1("PspExitNormalApc: [%p:%p], '%.16s')\n", 
+            PsGetCurrentThread(),
+            PsGetCurrentProcess(),
+            PsGetCurrentProcess()->ImageFileName);
 
     /* This should never happen */
-    ASSERT(!SystemArgument2);
-
-    /* If this is a system thread, we can safely kill it from Kernel-Mode */
-    if (PsIsSystemThread(Thread))
-    {
-        /* Get the Exit Status */
-        DPRINT1("Killing System Thread\n");
-        ExitStatus = (NTSTATUS)Apc->NormalContext;
-
-        /* Free the APC */
-        ExFreePool(Apc);
-
-        /* Exit the Thread */
-        PspExitThread(ExitStatus);
-    }
+    ASSERT(!(((ULONG_PTR)SystemArgument2) & 1));
 
     /* If we're here, this is not a System Thread, so kill it from User-Mode */
-    DPRINT("Initializing User-Mode APC\n");
+    DPRINT1("Initializing User-Mode APC\n");
     KeInitializeApc(Apc,
                     &Thread->Tcb,
                     OriginalApcEnvironment,
                     PsExitSpecialApc,
-                    NULL,
+                    PspExitApcRundown,
                     PspExitNormalApc,
                     UserMode,
                     NormalContext);
 
     /* Now insert the APC with the User-Mode Flag */
-    KeInsertQueueApc(Apc, Apc, (PVOID)UserMode, 2);
+    if (!(KeInsertQueueApc(Apc,
+                           Apc,
+                           (PVOID)((ULONG_PTR)SystemArgument2 | 1),
+                           2)))
+    {
+        /* Failed to insert, free the APC */
+        PspExitApcRundown(Apc);
+    }
 
-    /* Forcefully resume the thread */
-    KeForceResumeThread(&Thread->Tcb);
+    /* Set the APC Pending flag */
+    Thread->Tcb.ApcState.UserApcPending = TRUE;
 }
 
 /*
  * See "Windows Internals" - Chapter 13, Page 49
  */
-VOID
-STDCALL
+NTSTATUS
+NTAPI
 PspTerminateThreadByPointer(PETHREAD Thread,
-                            NTSTATUS ExitStatus)
+                            NTSTATUS ExitStatus,
+                            BOOLEAN bSelf)
 {
     PKAPC Apc;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Flags;
+    PAGED_CODE();
+    DPRINT1("PspTerminateThreadByPointer(%p, %lx)\n", Thread, ExitStatus);
 
-    DPRINT("PspTerminatedThreadByPointer(Thread %x, ExitStatus %x)\n",
-            Thread, ExitStatus);
+    /* Check if this is a Critical Thread, and Bugcheck */
+    if (Thread->BreakOnTermination)
+    {
+        /* FIXME: Add critical thread support */
+        DPRINT1("A critical thread is being terminated\n");
+        KEBUGCHECK(0);
+    }
+
+    /* Check if we are already inside the thread */
+    if (bSelf || (PsGetCurrentThread() == Thread))
+    {
+        /* This should only happen at passive */
+        ASSERT_IRQL(PASSIVE_LEVEL);
 
-    /* Check if we are already in the right context */
-    if (PsGetCurrentThread() == Thread) {
+        /* Mark it as terminated */
+        InterlockedOr(&Thread->CrossThreadFlags, 1);
 
         /* Directly terminate the thread */
         PspExitThread(ExitStatus);
+    }
 
-        /* we should never reach this point! */
-        KEBUGCHECK(0);
+    /* This shouldn't be a system thread */
+    if (Thread->SystemThread)
+    {
+        DPRINT1("A system thread is being illegaly terminated\n");
+        return STATUS_ACCESS_DENIED;
     }
 
     /* Allocate the APC */
     Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
 
-    /* Initialize a Kernel Mode APC to Kill the Thread */
-    KeInitializeApc(Apc,
-                    &Thread->Tcb,
-                    OriginalApcEnvironment,
-                    PsExitSpecialApc,
-                    NULL,
-                    PspExitNormalApc,
-                    KernelMode,
-                    (PVOID)ExitStatus);
+    /* Set the Terminated Flag */
+    Flags = Thread->CrossThreadFlags | 1;
 
-    /* Insert it into the APC Queue */
-    KeInsertQueueApc(Apc,
-                     Apc,
-                     NULL,
-                     2);
+    /* Set it, and check if it was already set while we were running */
+    if (!(InterlockedExchange(&Thread->CrossThreadFlags, Flags) & 1))
+    {
+        /* Initialize a Kernel Mode APC to Kill the Thread */
+        KeInitializeApc(Apc,
+                        &Thread->Tcb,
+                        OriginalApcEnvironment,
+                        PsExitSpecialApc,
+                        PspExitApcRundown,
+                        PspExitNormalApc,
+                        KernelMode,
+                        (PVOID)ExitStatus);
+
+        /* Insert it into the APC Queue */
+        if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
+        {
+            /* The APC was already in the queue, fail */
+            ExFreePool(Apc);
+            Status = STATUS_UNSUCCESSFUL;
+        }
+        else
+        {
+            /* Forcefully resume the thread and return */
+            KeForceResumeThread(&Thread->Tcb);
+            return Status;
+        }
+    }
 
-    /* Forcefully resume the thread */
-    KeForceResumeThread(&Thread->Tcb);
+    /* We failed, free the APC */
+    ExFreePool(Apc);
+
+    /* Return Status */
+    DPRINT1("Fail return: %lx\n", Status);
+    return Status;
 }
 
-NTSTATUS
-STDCALL
-PspExitProcess(PEPROCESS Process)
+VOID
+NTAPI
+PspExitProcess(IN BOOLEAN LastThread,
+               IN PEPROCESS Process)
 {
-    DPRINT("PspExitProcess 0x%x\n", Process);
+    ULONG Actual;
+    PAGED_CODE();
+    DPRINT1("PspExitProcess %p\n", Process);
 
-    PspRunCreateProcessNotifyRoutines(Process, FALSE);
+    /* Set Process Delete flag */
+    InterlockedOr(&Process->Flags, 4);
 
-    PspDestroyQuotaBlock(Process);
+    /* Check if we are the last thread */
+    if (LastThread)
+    {
+        /* Notify the WMI Process Callback */
+        //WmiTraceProcess(Process, FALSE);
+
+        /* Run the Notification Routines */
+        PspRunCreateProcessNotifyRoutines(Process, FALSE);
+    }
 
-    /* close all handles associated with our process, this needs to be done
-       when the last thread still runs */
-    ObKillProcess(Process);
+    /* Cleanup the power state */
+    PopCleanupPowerState((PPOWER_STATE)&Process->Pcb.PowerState);
+
+    /* Clear the security port */
+    if (!Process->SecurityPort)
+    {
+        /* So we don't double-dereference */
+        Process->SecurityPort = (PVOID)1;
+    }
+    else if (Process->SecurityPort != (PVOID)1)
+    {
+        /* Dereference it */
+        ObDereferenceObject(Process->SecurityPort);
+        Process->SecurityPort = (PVOID)1;
+    }
 
-    KeSetProcess(&Process->Pcb, IO_NO_INCREMENT);
+    /* Check if we are the last thread */
+    if (LastThread)
+    {
+        /* Check if we have to set the Timer Resolution */
+        if (Process->SetTimerResolution)
+        {
+            /* Set it to default */
+            ZwSetTimerResolution(KeMaximumIncrement, 0, &Actual);
+        }
     
-    /* release the keep-alive reference of the process object */
-    ObDereferenceObject(Process);
+        /*
+         * Check if we are part of a Job, and if the job has a completion port
+         */
+        if ((Process->Job) && (Process->Job->CompletionPort))
+        {
+            /* FIXME: Check job status code and do I/O completion if needed */
+        }
 
-    return(STATUS_SUCCESS);
+        /* FIXME: Notify the Prefetcher */
+    }
+    else
+    {
+        /* Clear process' address space here */
+        MmCleanProcessAddressSpace(Process);
+    }
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtTerminateProcess(IN HANDLE ProcessHandle  OPTIONAL,
                    IN NTSTATUS ExitStatus)
 {
     NTSTATUS Status;
-    PEPROCESS Process;
-    PETHREAD CurrentThread;
+    PEPROCESS Process, CurrentProcess = PsGetCurrentProcess();
+    PETHREAD Thread, CurrentThread = PsGetCurrentThread();
     BOOLEAN KillByHandle;
-
     PAGED_CODE();
-
-    DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
+    DPRINT1("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
             ProcessHandle, ExitStatus);
 
+    /* Remember how we will kill it */
     KillByHandle = (ProcessHandle != NULL);
 
     /* Get the Process Object */
-    Status = ObReferenceObjectByHandle((KillByHandle ? ProcessHandle : NtCurrentProcess()),
+    Status = ObReferenceObjectByHandle((KillByHandle) ?
+                                       ProcessHandle : NtCurrentProcess(),
                                        PROCESS_TERMINATE,
                                        PsProcessType,
                                        KeGetPreviousMode(),
                                        (PVOID*)&Process,
                                        NULL);
-    if (!NT_SUCCESS(Status)) {
-
+    if (!NT_SUCCESS(Status))
+    {
         DPRINT1("Invalid handle to Process\n");
         return(Status);
     }
 
-    CurrentThread = PsGetCurrentThread();
-
-    PsLockProcess(Process, FALSE);
-
-    if(Process->ExitTime.QuadPart != 0)
+    /* Check if this is a Critical Process, and Bugcheck */
+    if (Process->BreakOnTermination)
     {
-      PsUnlockProcess(Process);
-      ObDereferenceObject(Process);
-      return STATUS_PROCESS_IS_TERMINATING;
+        /* FIXME: Add critical Process support */
+        DPRINT1("A critical Process is being terminated\n");
+        KEBUGCHECK(0);
     }
 
-    /* Terminate all the Process's Threads */
-    PspTerminateProcessThreads(Process, ExitStatus);
+    /* Lock the Process */
+    PsLockProcess(Process, FALSE);
 
-    /* only kill the calling thread if it either passed a process handle or
-       NtCurrentProcess() */
-    if (KillByHandle) {
+    /* Set the exit flag */
+    if (!KillByHandle) InterlockedOr(&Process->Flags, 8);
 
-        /* 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);
-        Process->ExitStatus = ExitStatus;
+    /* Get the first thread */
+    Status = STATUS_NOTHING_TO_TERMINATE;
+    if ((Thread = PsGetNextProcessThread(Process, NULL)))
+    {
+        /* We know we have at least a thread */
+        Status = STATUS_SUCCESS;
 
-        /* Only master thread remains... kill it off */
-        if (CurrentThread->ThreadsProcess == Process) {
+        /* Loop and kill the others */
+        do
+        {
+            /* Ensure it's not ours*/
+            if (Thread != CurrentThread)
+            {
+                /* Kill it */
+                PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
+            }
 
-            /* mark our thread as terminating so attempts to terminate it, when
-               unlocking the process, fail */
-            CurrentThread->Terminated = TRUE;
+            /* Move to the next thread */
+        } while((Thread = PsGetNextProcessThread(Process, Thread)));
+    }
 
-            PsUnlockProcess(Process);
+    /* Unlock the process */
+    PsUnlockProcess(Process);
 
-            /* we can safely dereference the process because the current thread
-               holds a reference to it until it gets reaped */
-            ObDereferenceObject(Process);
+    /* Check if we are killing ourselves */
+    if (Process != CurrentProcess)
+    {
+        /* Check for the DBG_TERMINATE_PROCESS exit code */
+        if (ExitStatus == DBG_TERMINATE_PROCESS)
+        {
+            /* FIXME: Disable debugging on this process */
+        }
+    }
+    /* Make sure that we got a handle */
+    else if (KillByHandle)
+    {
+        /* Dereference the project */
+        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 */
+        /* Terminate ourselves */
+        PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE);
+    }
 
-            PspExitThread(ExitStatus);
+    /* Check if there was nothing to terminate, or if we have a Debug Port */
+    if ((Status == STATUS_NOTHING_TO_TERMINATE) ||
+        (Process->DebugPort && KillByHandle))
+    {
+        /* Clear the handle table */
+        DPRINT1("Clearing OB Table\n");
+        ObClearProcessHandleTable(Process);
 
-            /* we should never reach this point! */
-            KEBUGCHECK(0);
-        }
+        /* Return status now */
+        Status = STATUS_SUCCESS;
     }
 
-    /* unlock and dereference the process so the threads can kill themselves */
-    PsUnlockProcess(Process);
+    /* Decrease the reference count we added */
     ObDereferenceObject(Process);
 
-    return(STATUS_SUCCESS);
+    /* Return status */
+    DPRINT1("Returning: %lx\n", Status);
+    return Status;
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtTerminateThread(IN HANDLE ThreadHandle,
                   IN NTSTATUS ExitStatus)
 {
     PETHREAD Thread;
+    PETHREAD CurrentThread = PsGetCurrentThread();
     NTSTATUS Status;
-
     PAGED_CODE();
+    DPRINT1("NtTerminateThread: %lx %lx\n", ThreadHandle, ExitStatus);
     
     /* Handle the special NULL case */
     if (!ThreadHandle)
     {
         /* Check if we're the only thread left */
-        if (IsListEmpty(&PsGetCurrentProcess()->Pcb.ThreadListHead))
+        if (PsGetCurrentProcess()->ActiveThreads == 1)
         {
             /* This is invalid */
             DPRINT1("Can't terminate self\n");
@@ -646,105 +1079,79 @@ NtTerminateThread(IN HANDLE ThreadHandle,
         }
         else
         {
-            /* Use current handle */
-            ThreadHandle = NtCurrentThread();
+            /* Terminate us directly */
+            goto TerminateSelf;
         }
     }
+    else if (ThreadHandle == NtCurrentThread())
+    {
+TerminateSelf:
+        /* Terminate this thread */
+        return PspTerminateThreadByPointer(CurrentThread,
+                                           ExitStatus,
+                                           TRUE);
+    }
 
-    /* Get the Thread Object */
+    /* We are terminating another thread, get the Thread Object */
     Status = ObReferenceObjectByHandle(ThreadHandle,
                                        THREAD_TERMINATE,
                                        PsThreadType,
                                        KeGetPreviousMode(),
                                        (PVOID*)&Thread,
                                        NULL);
-    if (!NT_SUCCESS(Status)) {
-
+    if (!NT_SUCCESS(Status))
+    {
         DPRINT1("Could not reference thread object\n");
-        return(Status);
-    }
-
-    /* Make sure this is not a system thread */
-    if (PsIsSystemThread(Thread)) {
-
-        DPRINT1("Trying to Terminate a system thread!\n");
-        ObDereferenceObject(Thread);
-        return STATUS_INVALID_PARAMETER;
+        return Status;
     }
 
     /* Check to see if we're running in the same thread */
-    if (Thread != PsGetCurrentThread())  {
-
-        /* we need to lock the process to make sure it's not already terminating */
-        PsLockProcess(Thread->ThreadsProcess, FALSE);
-
-        /* This isn't our thread, terminate it if not already done */
-        if (!Thread->Terminated) {
-
-             Thread->Terminated = TRUE;
-
+    if (Thread != CurrentThread)
+    {
              /* Terminate it */
-             PspTerminateThreadByPointer(Thread, ExitStatus);
-        }
-
-        PsUnlockProcess(Thread->ThreadsProcess);
+        Status = PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
 
         /* Dereference the Thread and return */
         ObDereferenceObject(Thread);
-
-    } else {
-
-        Thread->Terminated = TRUE;
-
-        /* 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 */
+    }
+    else
+    {
+        /* Dereference the thread and terminate ourselves */
         ObDereferenceObject(Thread);
-
-        /* Terminate him, he's ours */
-        PspExitThread(ExitStatus);
-
-        /* We do never reach this point */
-        KEBUGCHECK(0);
+        goto TerminateSelf;
     }
 
-    return(STATUS_SUCCESS);
+    return Status;
 }
 
 /*
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsTerminateSystemThread(NTSTATUS ExitStatus)
 {
     PETHREAD Thread = PsGetCurrentThread();
 
     /* Make sure this is a system thread */
-    if (!PsIsSystemThread(Thread)) {
-
+    if (Thread->SystemThread)
+    {
         DPRINT1("Trying to Terminate a non-system thread!\n");
         return STATUS_INVALID_PARAMETER;
     }
 
     /* Terminate it for real */
-    PspExitThread(ExitStatus);
-
-    /* we should never reach this point! */
-    KEBUGCHECK(0);
-
-    return(STATUS_SUCCESS);
+    return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE);
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtRegisterThreadTerminatePort(HANDLE PortHandle)
 {
     NTSTATUS Status;
     PTERMINATION_PORT TerminationPort;
     PVOID TerminationLpcPort;
     PETHREAD Thread;
-
     PAGED_CODE();
 
     /* Get the Port */
@@ -768,10 +1175,8 @@ NtRegisterThreadTerminatePort(HANDLE PortHandle)
         /* Associate the Port */
         Thread = PsGetCurrentThread();
         TerminationPort->Port = TerminationLpcPort;
-        DPRINT("TerminationPort: %p\n", TerminationPort);
         TerminationPort->Next = Thread->TerminationPort;
         Thread->TerminationPort = TerminationPort;
-        DPRINT("TerminationPort: %p\n", Thread->TerminationPort);
 
         /* Return success */
         return(STATUS_SUCCESS);
index 628f7e2..0ddcc09 100644 (file)
@@ -1,11 +1,10 @@
 /*
- * 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/process.c
- * PURPOSE:         Process managment
- *
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
- *                  David Welch (welch@cwcom.net)
+ * PURPOSE:         Process Manager: Process Management
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Thomas Weidenmueller (w3seek@reactos.org
  */
 
 /* INCLUDES ******************************************************************/
@@ -24,15 +23,34 @@ PEPROCESS PsInitialSystemProcess = NULL;
 PEPROCESS PsIdleProcess = NULL;
 POBJECT_TYPE PsProcessType = NULL;
 extern PHANDLE_TABLE PspCidTable;
+extern POBJECT_TYPE DbgkDebugObjectType;
 
 EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
 
+ULONG PsMinimumWorkingSet, PsMaximumWorkingSet;
+
 LIST_ENTRY PsActiveProcessHead;
 FAST_MUTEX PspActiveProcessMutex;
 LARGE_INTEGER ShortPsLockDelay, PsLockTimeout;
 
 /* INTERNAL FUNCTIONS *****************************************************************/
 
+NTSTATUS
+NTAPI
+PspDeleteLdt(PEPROCESS Process)
+{
+    /* FIXME */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PspDeleteVdmObjects(PEPROCESS Process)
+{
+    /* FIXME */
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS
 NTAPI
 PsLockProcess(PEPROCESS Process, BOOLEAN Timeout)
@@ -109,12 +127,59 @@ PsUnlockProcess(PEPROCESS Process)
   KeLeaveCriticalRegion();
 }
 
+PETHREAD
+NTAPI
+PsGetNextProcessThread(IN PEPROCESS Process,
+                       IN PETHREAD Thread OPTIONAL)
+{
+    PETHREAD FoundThread = NULL;
+    PLIST_ENTRY ListHead, Entry;
+    PAGED_CODE();
+
+    /* Lock the process */
+    PsLockProcess(Process, FALSE);
+
+    /* Check if we're already starting somewhere */
+    if (Thread)
+    {
+        /* Start where we left off */
+        Entry = Thread->ThreadListEntry.Flink;
+    }
+    else
+    {
+        /* Start at the beginning */
+        Entry = Process->ThreadListHead.Flink;
+    }
+
+    /* Set the list head and start looping */
+    ListHead = &Process->ThreadListHead;
+    while (ListHead != Entry)
+    {
+        /* Get the Thread */
+        FoundThread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
+
+        /* Reference the thread. FIXME: Race, use ObSafeReferenceObject */
+        ObReferenceObject(FoundThread);
+        break;
+    }
+
+    /* Unlock the process */
+    PsUnlockProcess(Process);
+
+    /* Check if we had a starting thread, and dereference it */
+    if (Thread) ObDereferenceObject(Thread);
+
+    /* Return what we found */
+    return FoundThread;
+}
+
 PEPROCESS
-STDCALL
+NTAPI
 PsGetNextProcess(PEPROCESS OldProcess)
 {
     PEPROCESS NextProcess;
     NTSTATUS Status;
+    PAGED_CODE();
 
     /* Check if we have a previous process */
     if (OldProcess == NULL)
@@ -176,59 +241,77 @@ PsGetNextProcess(PEPROCESS OldProcess)
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 PspCreateProcess(OUT PHANDLE ProcessHandle,
                  IN ACCESS_MASK DesiredAccess,
                  IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
                  IN HANDLE ParentProcess  OPTIONAL,
-                 IN BOOLEAN InheritObjectTable,
+                 IN DWORD Flags,
                  IN HANDLE SectionHandle  OPTIONAL,
                  IN HANDLE DebugPort  OPTIONAL,
-                 IN HANDLE ExceptionPort  OPTIONAL)
+                 IN HANDLE ExceptionPort OPTIONAL,
+                 IN BOOLEAN InJob)
 {
     HANDLE hProcess;
-    PEPROCESS Process = NULL;
-    PEPROCESS pParentProcess = NULL;
-    PEPORT pDebugPort = NULL;
-    PEPORT pExceptionPort = NULL;
-    PSECTION_OBJECT SectionObject = NULL;
-    NTSTATUS Status = STATUS_SUCCESS;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PEPROCESS Process, Parent;
+    PEPORT ExceptionPortObject;
+    PDBGK_DEBUG_OBJECT DebugObject;
+    PSECTION_OBJECT SectionObject;
+    NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode;
     PHYSICAL_ADDRESS DirectoryTableBase;
     KAFFINITY Affinity;
     HANDLE_TABLE_ENTRY CidEntry;
-    BOOLEAN ProcessCreated = FALSE;
+    PETHREAD CurrentThread;
+    PEPROCESS CurrentProcess;
+    ULONG MinWs, MaxWs;
+    PAGED_CODE();
+    DirectoryTableBase.QuadPart = 0;
 
-       DirectoryTableBase.QuadPart = (ULONGLONG)0;
+    /* Get the current thread, process and cpu ring mode */
+    CurrentThread = PsGetCurrentThread();
+    ASSERT(&CurrentThread->Tcb == KeGetCurrentThread());
+    PreviousMode = ExGetPreviousMode();
+    ASSERT((CurrentThread) == PsGetCurrentThread());
+    CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
 
-    DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes);
+    /* Validate flags */
+    if (Flags & ~PS_ALL_FLAGS) return STATUS_INVALID_PARAMETER;
 
-    /* Reference the Parent if there is one */
-    if(ParentProcess != NULL)
+    /* Check for parent */
+    if(ParentProcess)
     {
+        /* Reference it */
         Status = ObReferenceObjectByHandle(ParentProcess,
                                            PROCESS_CREATE_PROCESS,
                                            PsProcessType,
                                            PreviousMode,
-                                           (PVOID*)&pParentProcess,
+                                           (PVOID*)&Parent,
                                            NULL);
-
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status);
-            goto Cleanup;
+            return Status;
         }
 
-        /* Inherit Parent process's Affinity. */
-        Affinity = pParentProcess->Pcb.Affinity;
+        /* If this process should be in a job but the parent isn't */
+        if ((InJob) && (!Parent->Job))
+        {
+            /* This is illegal. Dereference the parent and fail */
+            ObDereferenceObject(Parent);
+            return STATUS_INVALID_PARAMETER;
+        }
 
+        /* Inherit Parent process's Affinity. */
+        Affinity = Parent->Pcb.Affinity;
     }
     else
     {
-        pParentProcess = NULL;
+        /* We have no parent */
+        Parent = NULL;
 #ifdef CONFIG_SMP        
-   /* FIXME:
-    *   Only the boot cpu is initialized in the early boot phase. 
+        /*
+         * FIXME: Only the boot cpu is initialized in the early boot phase. 
     */
         Affinity = 0xffffffff;
 #else
@@ -236,42 +319,55 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
 #endif
     }
 
-    /* Add the debug port */
-    if (DebugPort != NULL)
+    /* Save working set data */
+    MinWs = PsMinimumWorkingSet;
+    MaxWs = PsMaximumWorkingSet;
+
+    /* Create the Object */
+    Status = ObCreateObject(PreviousMode,
+                            PsProcessType,
+                            ObjectAttributes,
+                            PreviousMode,
+                            NULL,
+                            sizeof(EPROCESS),
+                            0,
+                            0,
+                            (PVOID*)&Process);
+    if (!NT_SUCCESS(Status))
     {
-        Status = ObReferenceObjectByHandle(DebugPort,
-                                           PORT_ALL_ACCESS,
-                                           LpcPortObjectType,
-                                           PreviousMode,
-                                           (PVOID*)&pDebugPort,
-                                           NULL);
-        if (!NT_SUCCESS(Status))
-        {
-                DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status);
-                goto Cleanup;
-        }
+        DPRINT1("Failed to create process object, Status: 0x%x\n", Status);
+        goto Cleanup;
     }
 
-    /* Add the exception port */
-    if (ExceptionPort != NULL)
-    {
-        Status = ObReferenceObjectByHandle(ExceptionPort,
-                                           PORT_ALL_ACCESS,
-                                           LpcPortObjectType,
-                                           PreviousMode,
-                                           (PVOID*)&pExceptionPort,
-                                           NULL);
+    /* Clean up the Object */
+    RtlZeroMemory(Process, sizeof(EPROCESS));
 
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status);
-            goto Cleanup;
-        }
+    /* Setup the Thread List Head */
+    InitializeListHead(&Process->ThreadListHead);
+
+    /* Set up the Quota Block from the Parent */
+    PspInheritQuota(Process, Parent);
+
+    /* Set up Dos Device Map from the Parent */
+    ObInheritDeviceMap(Parent, Process);
+
+    /* Check if we have a parent */
+    if (Parent)
+    {
+        /* Ineherit PID and Hard Error Processing */
+        Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
+        Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;
+    }
+    else
+    {
+        /* Use default hard error processing */
+        Process->DefaultHardErrorProcessing = TRUE;
     }
 
-    /* Add the Section */
-    if (SectionHandle != NULL)
+    /* Check for a section handle */
+    if (SectionHandle)
     {
+        /* Get a pointer to it */
         Status = ObReferenceObjectByHandle(SectionHandle,
                                            SECTION_MAP_EXECUTE,
                                            MmSectionObjectType,
@@ -281,180 +377,257 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status);
-            goto Cleanup;
+            goto CleanupWithRef;
         }
     }
+    else
+    {
+        /* Is the parent the initial process? */
+        if (Parent != PsInitialSystemProcess)
+        {
+            /* It's not, so acquire the process rundown */
+            // FIXME
 
-    /* Create the Object */
-    DPRINT("Creating Process Object\n");
-    Status = ObCreateObject(PreviousMode,
-                            PsProcessType,
-                            ObjectAttributes,
-                            PreviousMode,
-                            NULL,
-                            sizeof(EPROCESS),
-                            0,
-                            0,
-                            (PVOID*)&Process);
+            /* If the parent has a section, use it */
+            SectionObject = Parent->SectionObject;
+            if (SectionObject) ObReferenceObject(SectionObject);
 
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Failed to create process object, Status: 0x%x\n", Status);
-        goto Cleanup;
+            /* Release process rundown */
+            // FIXME
+
+            /* If we don't have a section object */
+            if (!SectionObject)
+            {
+                /* Then the process is in termination, so fail */
+                Status = STATUS_PROCESS_IS_TERMINATING;
+                goto CleanupWithRef;
+            }
+        }
     }
 
-    /* Clean up the Object */
-    DPRINT("Cleaning Process Object\n");
-    RtlZeroMemory(Process, sizeof(EPROCESS));
+    /* Save the pointer to the section object */
+    Process->SectionObject = SectionObject;
 
-    /* Inherit stuff from the Parent since we now have the object created */
-    if (pParentProcess)
+    /* Check for the debug port */
+    if (DebugPort)
     {
-        Process->InheritedFromUniqueProcessId = pParentProcess->UniqueProcessId;
-        Process->Session = pParentProcess->Session;
-    }
+        /* Reference it */
+        Status = ObReferenceObjectByHandle(DebugPort,
+                                           DEBUG_OBJECT_ADD_REMOVE_PROCESS,
+                                           DbgkDebugObjectType,
+                                           PreviousMode,
+                                           (PVOID*)&DebugObject,
+                                           NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status);
+            goto CleanupWithRef;
+        }
 
-    /* Set up the Quota Block from the Parent */
-    PspInheritQuota(Process, pParentProcess);
+        /* Save the debug object */
+        Process->DebugPort = DebugObject;
+
+        /* Check if the caller doesn't want the debug stuff inherited */
+        if (Flags & PS_NO_DEBUG_INHERIT) InterlockedOr(&Process->Flags, 2);
+    }
+    else
+    {
+        /* Do we have a parent? Copy his debug port */
+        if (Parent) DbgkCopyProcessDebugPort(Process, Parent);
+    }
 
-    /* FIXME: Set up Dos Device Map from the Parent
-    ObInheritDeviceMap(Parent, Process) */
+    /* Now check for an exception port */
+    if (ExceptionPort)
+    {
+        /* Reference it */
+        Status = ObReferenceObjectByHandle(ExceptionPort,
+                                           PORT_ALL_ACCESS,
+                                           LpcPortObjectType,
+                                           PreviousMode,
+                                           (PVOID*)&ExceptionPortObject,
+                                           NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status);
+            goto CleanupWithRef;
+        }
 
-    /* Set the Process' LPC Ports */
-    Process->DebugPort = pDebugPort;
-    Process->ExceptionPort = pExceptionPort;
+        /* Save the exception port */
+        Process->ExceptionPort = ExceptionPortObject;
+    }
 
     /* Save the pointer to the section object */
     Process->SectionObject = SectionObject;
 
     /* Setup the Lock Event */
-    DPRINT("Initialzing Process Lock\n");
     Process->LockEvent = ExAllocatePoolWithTag(PagedPool,
-                                                                sizeof(KEVENT),
-                                                                TAG('P', 's', 'L', 'k'));
+                                               sizeof(KEVENT),
+                                               TAG('P', 's', 'L', 'k'));
     KeInitializeEvent(Process->LockEvent, SynchronizationEvent, FALSE);
 
-    /* Setup the Thread List Head */
-    DPRINT("Initialzing Process ThreadListHead\n");
-    InitializeListHead(&Process->ThreadListHead);
+    /* Set default exit code */
+    Process->ExitStatus = STATUS_TIMEOUT;
 
     /* Create or Clone the Handle Table */
-    DPRINT("Initialzing Process Handle Table\n");
-    ObpCreateHandleTable(pParentProcess, Process);
-    DPRINT("Handle Table: %x\n", Process->ObjectTable);
+    ObpCreateHandleTable(Parent, Process);
 
     /* Set Process's Directory Base */
-    DPRINT("Initialzing Process Directory Base\n");
-    MmCopyMmInfo((pParentProcess ? pParentProcess : PsInitialSystemProcess),
+    MmCopyMmInfo(Parent ? Parent : PsInitialSystemProcess,
                  Process,
                  &DirectoryTableBase);
 
+    /* We now have an address space */
+    InterlockedOr(&Process->Flags, 0x40000);
+
+    /* Set the maximum WS */
+    Process->Vm.MaximumWorkingSetSize = MaxWs;
+
     /* Now initialize the Kernel Process */
-    DPRINT("Initialzing Kernel Process\n");
     KeInitializeProcess(&Process->Pcb,
                         PROCESS_PRIORITY_NORMAL,
                         Affinity,
                         DirectoryTableBase);
 
     /* Duplicate Parent Token */
-    DPRINT("Initialzing Process Token\n");
-    Status = PspInitializeProcessSecurity(Process, pParentProcess);
+    Status = PspInitializeProcessSecurity(Process, Parent);
     if (!NT_SUCCESS(Status))
     {
-        DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status);
-        goto Cleanup;
+        DPRINT1("PspInitializeProcessSecurity failed (Status %x)\n", Status);
+        goto CleanupWithRef;
     }
 
+    /* Set default priority class */
+    Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
+
     /* Create the Process' Address Space */
-    DPRINT("Initialzing Process Address Space\n");
     Status = MmCreateProcessAddressSpace(Process, (PROS_SECTION_OBJECT)SectionObject);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to create Address Space\n");
-        goto Cleanup;
+        goto CleanupWithRef;
+    }
+
+    /* Check for parent again */
+#if 0
+    if (!Parent)
+    {
+        /* Allocate our Audit info */
+        Process->SeAuditProcessCreationInfo.ImageFileName = 
+            ExAllocatePoolWithTag(PagedPool,
+                                  sizeof(SE_AUDIT_PROCESS_CREATION_INFO),
+                                  TAG_SEPA);
+        RtlZeroMemory(Process->SeAuditProcessCreationInfo.ImageFileName,
+                      sizeof(SE_AUDIT_PROCESS_CREATION_INFO));
     }
+    else
+    {
+        /* Allocate our Audit info */
+        Process->SeAuditProcessCreationInfo.ImageFileName = 
+            ExAllocatePoolWithTag(PagedPool,
+                                  sizeof(SE_AUDIT_PROCESS_CREATION_INFO) + 
+                                  Parent->SeAuditProcessCreationInfo.
+                                  ImageFileName->Name.MaximumLength,
+                                  TAG_SEPA);
+
+        /* Copy from parent */
+        RtlCopyMemory(Process->SeAuditProcessCreationInfo.ImageFileName,
+                      Parent->SeAuditProcessCreationInfo.ImageFileName,
+                      sizeof(SE_AUDIT_PROCESS_CREATION_INFO) + 
+                      Parent->SeAuditProcessCreationInfo.ImageFileName->
+                      Name.MaximumLength);
+
+        /* Update buffer pointer */
+        Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer = 
+            (PVOID)(Process->SeAuditProcessCreationInfo.ImageFileName + 1);
+    }
+#endif
 
+    /* Check if we have a section object */
     if (SectionObject)
     {
         /* Map the System Dll */
-        DPRINT("Mapping System DLL\n");
         PspMapSystemDll(Process, NULL);
     }
 
     /* Create a handle for the Process */
-    DPRINT("Initialzing Process CID Handle\n");
     CidEntry.Object = Process;
     CidEntry.GrantedAccess = 0;
     Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
-    DPRINT("Created CID: %d\n", Process->UniqueProcessId);
     if(!Process->UniqueProcessId)
     {
         DPRINT1("Failed to create CID handle\n");
-        Status = STATUS_UNSUCCESSFUL; /* FIXME - what error should we return? */
-        goto Cleanup;
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto CleanupWithRef;
     }
 
     /* FIXME: Insert into Job Object */
 
     /* Create PEB only for User-Mode Processes */
-    if (pParentProcess)
+    if (Parent)
     {
-        DPRINT("Creating PEB\n");
         Status = MmCreatePeb(Process);
         if (!NT_SUCCESS(Status))
         {
-            DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
-            goto Cleanup;
+            DPRINT("NtCreateProcess() Peb creation failed: Status %x\n",Status);
+            goto CleanupWithRef;
         }
     }
 
-    /* W00T! The process can now be activated */
-    DPRINT("Inserting into Active Process List\n");
+    /* The process can now be activated */
     ExAcquireFastMutex(&PspActiveProcessMutex);
     InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks);
     ExReleaseFastMutex(&PspActiveProcessMutex);
-    
-    ProcessCreated = TRUE;
 
     /* FIXME: SeCreateAccessStateEx */
 
     /* Insert the Process into the Object Directory */
-    DPRINT("Inserting Process Object\n");
     Status = ObInsertObject(Process,
                             NULL,
                             DesiredAccess,
                             1,
                             (PVOID*)&Process,
                             &hProcess);
+
+    /* FIXME: Compute Quantum and Priority */
+
+    /* 
+     * FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
+     *        SeAccessCheck
+     */
+    ObReferenceObject(Process); // <- Act as if we called ObGetObjectSecurity
+
+    /* Check for success */
     if (NT_SUCCESS(Status))
     {
         /* Set the Creation Time */
         KeQuerySystemTime(&Process->CreateTime);
 
-        DPRINT("Done. Returning handle: %x\n", hProcess);
+        /* Protect against bad user-mode pointer */
         _SEH_TRY
         {
+            /* Save the process handle */
            *ProcessHandle = hProcess;
         }
         _SEH_HANDLE
         {
            Status = _SEH_GetExceptionCode();
-        } _SEH_END;
-        /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
-                  SeAccessCheck
-        */
+        }
+        _SEH_END;
     }
 
+CleanupWithRef:
+    /* 
+     * Dereference the process. For failures, kills the process and does
+     * cleanup present in PspDeleteProcess. For success, kills the extra
+     * reference added by ObGetObjectSecurity
+     */
+    ObDereferenceObject(Process);
+
 Cleanup:
-    if(pParentProcess != NULL) ObDereferenceObject(pParentProcess);
-    if(SectionObject != NULL) ObDereferenceObject(SectionObject);
-    if (!ProcessCreated)
-    {
-        if(pExceptionPort != NULL) ObDereferenceObject(pExceptionPort);
-        if(pDebugPort != NULL) ObDereferenceObject(pDebugPort);
-        if(Process != NULL) ObDereferenceObject(Process);
-    }
+    /* Dereference the parent */
+    if (Parent) ObDereferenceObject(Parent);
 
+    /* Return status to caller */
     return Status;
 }
 
@@ -464,7 +637,7 @@ Cleanup:
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsCreateSystemProcess(PHANDLE ProcessHandle,
                       ACCESS_MASK DesiredAccess,
                       POBJECT_ATTRIBUTES ObjectAttributes)
@@ -472,18 +645,19 @@ PsCreateSystemProcess(PHANDLE ProcessHandle,
     return PspCreateProcess(ProcessHandle,
                             DesiredAccess,
                             ObjectAttributes,
-                            NULL, /* no parent process */
-                            FALSE,
+                            NULL,
+                            0,
                             NULL,
                             NULL,
-                            NULL);
+                            NULL,
+                            FALSE);
 }
 
 /*
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsLookupProcessByProcessId(IN HANDLE ProcessId,
                            OUT PEPROCESS *Process)
 {
@@ -491,7 +665,6 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId,
     PEPROCESS FoundProcess;
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
     PAGED_CODE();
-    
     KeEnterCriticalRegion();
 
     /* Get the CID Handle Entry */
@@ -513,10 +686,9 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId,
         /* Unlock the Entry */
         ExUnlockHandleTableEntry(PspCidTable, CidEntry);
     }
-    
-    KeLeaveCriticalRegion();
 
     /* Return to caller */
+    KeLeaveCriticalRegion();
     return Status;
 }
 
@@ -524,7 +696,7 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
                            OUT PEPROCESS *Process OPTIONAL,
                            OUT PETHREAD *Thread)
@@ -533,7 +705,6 @@ PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
     PETHREAD FoundThread;
     NTSTATUS Status = STATUS_INVALID_CID;
     PAGED_CODE();
-    
     KeEnterCriticalRegion();
 
     /* Get the CID Handle Entry */
@@ -565,9 +736,8 @@ PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
         ExUnlockHandleTableEntry(PspCidTable, CidEntry);
     }
     
-    KeLeaveCriticalRegion();
-
     /* Return to caller */
+    KeLeaveCriticalRegion();
     return Status;
 }
 
@@ -605,7 +775,7 @@ PsGetProcessExitTime(VOID)
  * @implemented
  */
 LONGLONG
-STDCALL
+NTAPI
 PsGetProcessCreateTimeQuadPart(PEPROCESS Process)
 {
     return Process->CreateTime.QuadPart;
@@ -615,7 +785,7 @@ PsGetProcessCreateTimeQuadPart(PEPROCESS Process)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetProcessDebugPort(PEPROCESS Process)
 {
     return Process->DebugPort;
@@ -625,7 +795,7 @@ PsGetProcessDebugPort(PEPROCESS Process)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 PsGetProcessExitProcessCalled(PEPROCESS Process)
 {
     return Process->ProcessExiting;
@@ -635,7 +805,7 @@ PsGetProcessExitProcessCalled(PEPROCESS Process)
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsGetProcessExitStatus(PEPROCESS Process)
 {
     return Process->ExitStatus;
@@ -645,7 +815,7 @@ PsGetProcessExitStatus(PEPROCESS Process)
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetProcessId(PEPROCESS Process)
 {
     return (HANDLE)Process->UniqueProcessId;
@@ -655,7 +825,7 @@ PsGetProcessId(PEPROCESS Process)
  * @implemented
  */
 LPSTR
-STDCALL
+NTAPI
 PsGetProcessImageFileName(PEPROCESS Process)
 {
     return (LPSTR)Process->ImageFileName;
@@ -665,7 +835,7 @@ PsGetProcessImageFileName(PEPROCESS Process)
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)
 {
     return Process->InheritedFromUniqueProcessId;
@@ -675,7 +845,7 @@ PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)
  * @implemented
  */
 PEJOB
-STDCALL
+NTAPI
 PsGetProcessJob(PEPROCESS Process)
 {
     return Process->Job;
@@ -685,7 +855,7 @@ PsGetProcessJob(PEPROCESS Process)
  * @implemented
  */
 PPEB
-STDCALL
+NTAPI
 PsGetProcessPeb(PEPROCESS Process)
 {
     return Process->Peb;
@@ -695,7 +865,7 @@ PsGetProcessPeb(PEPROCESS Process)
  * @implemented
  */
 ULONG
-STDCALL
+NTAPI
 PsGetProcessPriorityClass(PEPROCESS Process)
 {
     return Process->PriorityClass;
@@ -714,7 +884,7 @@ PsGetCurrentProcessId(VOID)
  * @implemented
  */
 ULONG
-STDCALL
+NTAPI
 PsGetCurrentProcessSessionId(VOID)
 {
     return PsGetCurrentProcess()->Session;
@@ -724,7 +894,7 @@ PsGetCurrentProcessSessionId(VOID)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetProcessSectionBaseAddress(PEPROCESS Process)
 {
     return Process->SectionBaseAddress;
@@ -734,7 +904,7 @@ PsGetProcessSectionBaseAddress(PEPROCESS Process)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetProcessSecurityPort(PEPROCESS Process)
 {
     return Process->SecurityPort;
@@ -744,7 +914,7 @@ PsGetProcessSecurityPort(PEPROCESS Process)
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetProcessSessionId(PEPROCESS Process)
 {
     return (HANDLE)Process->Session;
@@ -768,7 +938,7 @@ PsGetWin32Process(VOID)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetProcessWin32Process(PEPROCESS Process)
 {
     return Process->Win32Process;
@@ -778,7 +948,7 @@ PsGetProcessWin32Process(PEPROCESS Process)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetProcessWin32WindowStation(PEPROCESS Process)
 {
     return Process->Win32WindowStation;
@@ -798,7 +968,7 @@ PsIsProcessBeingDebugged(PEPROCESS Process)
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 PsSetProcessPriorityClass(PEPROCESS Process,
                           ULONG PriorityClass)
 {
@@ -809,7 +979,7 @@ PsSetProcessPriorityClass(PEPROCESS Process,
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 PsSetProcessSecurityPort(PEPROCESS Process,
                          PVOID SecurityPort)
 {
@@ -820,7 +990,7 @@ PsSetProcessSecurityPort(PEPROCESS Process,
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 PsSetProcessWin32Process(PEPROCESS Process,
                          PVOID Win32Process)
 {
@@ -831,7 +1001,7 @@ PsSetProcessWin32Process(PEPROCESS Process,
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 PsSetProcessWindowStation(PEPROCESS Process,
                           PVOID WindowStation)
 {
@@ -842,7 +1012,7 @@ PsSetProcessWindowStation(PEPROCESS Process,
  * @unimplemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsSetProcessPriorityByClass(IN PEPROCESS Process,
                             IN ULONG Type)
 {
@@ -851,38 +1021,19 @@ PsSetProcessPriorityByClass(IN PEPROCESS Process,
 }
 
 /*
- * FUNCTION: Creates a process.
- * ARGUMENTS:
- *        ProcessHandle (OUT) = Caller supplied storage for the resulting
- *                              handle
- *        DesiredAccess = Specifies the allowed or desired access to the
- *                        process can be a combination of
- *                        STANDARD_RIGHTS_REQUIRED| ..
- *        ObjectAttribute = Initialized attributes for the object, contains
- *                          the rootdirectory and the filename
- *        ParentProcess = Handle to the parent process.
- *        InheritObjectTable = Specifies to inherit the objects of the parent
- *                             process if true.
- *        SectionHandle = Handle to a section object to back the image file
- *        DebugPort = Handle to a DebugPort if NULL the system default debug
- *                    port will be used.
- *        ExceptionPort = Handle to a exception port.
- * REMARKS:
- *        This function maps to the win32 CreateProcess.
- * RETURNS: Status
- *
  * @implemented
  */
 NTSTATUS
-STDCALL
-NtCreateProcess(OUT PHANDLE ProcessHandle,
-                IN ACCESS_MASK DesiredAccess,
-                IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
-                IN HANDLE ParentProcess,
-                IN BOOLEAN InheritObjectTable,
-                IN HANDLE SectionHandle  OPTIONAL,
-                IN HANDLE DebugPort  OPTIONAL,
-                IN HANDLE ExceptionPort  OPTIONAL)
+NTAPI
+NtCreateProcessEx(OUT PHANDLE ProcessHandle,
+                  IN ACCESS_MASK DesiredAccess,
+                  IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
+                  IN HANDLE ParentProcess,
+                  IN ULONG Flags,
+                  IN HANDLE SectionHandle OPTIONAL,
+                  IN HANDLE DebugPort OPTIONAL,
+                  IN HANDLE ExceptionPort OPTIONAL,
+                  IN BOOLEAN InJob)
 {
     KPROCESSOR_MODE PreviousMode  = ExGetPreviousMode();
     NTSTATUS Status = STATUS_SUCCESS;
@@ -906,7 +1057,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
     }
 
     /* Make sure there's a parent process */
-    if(ParentProcess == NULL)
+    if(!ParentProcess)
     {
         /* Can't create System Processes like this */
         Status = STATUS_INVALID_PARAMETER;
@@ -918,10 +1069,11 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
                                   DesiredAccess,
                                   ObjectAttributes,
                                   ParentProcess,
-                                  InheritObjectTable,
+                                  Flags,
                                   SectionHandle,
                                   DebugPort,
-                                  ExceptionPort);
+                                  ExceptionPort,
+                                  InJob);
     }
 
     /* Return Status */
@@ -932,11 +1084,44 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
+NtCreateProcess(OUT PHANDLE ProcessHandle,
+                IN ACCESS_MASK DesiredAccess,
+                IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
+                IN HANDLE ParentProcess,
+                IN BOOLEAN InheritObjectTable,
+                IN HANDLE SectionHandle  OPTIONAL,
+                IN HANDLE DebugPort  OPTIONAL,
+                IN HANDLE ExceptionPort  OPTIONAL)
+{
+    ULONG Flags = 0;
+
+    /* Set new-style flags */
+    if ((ULONG)SectionHandle & 1) Flags = PS_REQUEST_BREAKAWAY;
+    if ((ULONG)DebugPort & 1) Flags |= PS_NO_DEBUG_INHERIT;
+    if (InheritObjectTable) Flags |= PS_INHERIT_HANDLES;
+
+    /* Call the new API */
+    return NtCreateProcessEx(ProcessHandle,
+                             DesiredAccess,
+                             ObjectAttributes,
+                             ParentProcess,
+                             Flags,
+                             SectionHandle,
+                             DebugPort,
+                             ExceptionPort,
+                             FALSE);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
 NtOpenProcess(OUT PHANDLE ProcessHandle,
-              IN  ACCESS_MASK DesiredAccess,
-              IN  POBJECT_ATTRIBUTES ObjectAttributes,
-              IN  PCLIENT_ID ClientId)
+              IN ACCESS_MASK DesiredAccess,
+              IN POBJECT_ATTRIBUTES ObjectAttributes,
+              IN PCLIENT_ID ClientId)
 {
     KPROCESSOR_MODE PreviousMode;
     CLIENT_ID SafeClientId;
@@ -997,11 +1182,9 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
     }
 
     /* Open by name if one was given */
-    DPRINT("Checking type\n");
     if (HasObjectName)
     {
         /* Open it */
-        DPRINT("Opening by name\n");
         Status = ObOpenObjectByName(ObjectAttributes,
                                     PsProcessType,
                                     PreviousMode,
@@ -1021,7 +1204,6 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
         if (ClientId->UniqueThread)
         {
             /* Get the Process */
-            DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread);
             Status = PsLookupProcessThreadByCid(ClientId,
                                                 &Process,
                                                 &Thread);
@@ -1029,7 +1211,6 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
         else
         {
             /* Get the Process */
-            DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess);
             Status = PsLookupProcessByProcessId(ClientId->UniqueProcess,
                                                 &Process);
         }
index d1b32f6..c2aea28 100644 (file)
@@ -64,15 +64,6 @@ NTSTATUS STDCALL INIT_FUNCTION PspLookupKernelUserEntryPoints(VOID);
 
 /* FUNCTIONS ***************************************************************/
 
-VOID
-NTAPI
-PiShutdownProcessManager(VOID)
-{
-   DPRINT("PiShutdownProcessManager()\n");
-
-   PspKillMostProcesses();
-}
-
 VOID
 INIT_FUNCTION
 NTAPI
index cb64047..f61028d 100644 (file)
@@ -39,6 +39,40 @@ PspUnlockProcessSecurityShared(PEPROCESS Process)
     KeLeaveGuardedRegion();
 }
 
+VOID
+NTAPI
+PspDeleteProcessSecurity(IN PEPROCESS Process)
+{
+    /* Check if we have a token */
+    if (Process->Token.Object)
+    {
+        /* Deassign it */
+        SeDeassignPrimaryToken(Process);
+        Process->Token.Object = NULL;
+    }
+}
+
+VOID
+NTAPI
+PspDeleteThreadSecurity(IN PETHREAD Thread)
+{
+    /* Check if we have active impersonation info */
+    if (Thread->ActiveImpersonationInfo)
+    {
+        /* Dereference its token */
+        ObDereferenceObject(Thread->ImpersonationInfo->Token);
+    }
+
+    /* Check if we have impersonation info */
+    if (Thread->ImpersonationInfo)
+    {
+        /* Free it */
+        ExFreePool(Thread->ImpersonationInfo);
+        Thread->ActiveImpersonationInfo = FALSE;
+        Thread->ImpersonationInfo = NULL;
+    }
+}
+
 /* FUNCTIONS *****************************************************************/
 
 /*
index 4c40289..37a7ab9 100644 (file)
@@ -1,11 +1,23 @@
 /*
- * 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
+ */
+
+/*
+ * Alex FIXMEs:
+ *  - CRITICAL: NtCurrentTeb returns KPCR.
+ *  - CRITICAL: Verify rundown APIs (ex/rundown.c) and use them where necessary.
+ *  - MAJOR: Implement Pushlocks and use them as process lock.
+ *  - MAJOR: Implement Safe Referencing (See PsGetNextProcess/Thread).
+ *  - MAJOR: Implement Fast Referencing (mostly for tokens).
+ *  - MAJOR: Use Guarded Mutex instead of Fast Mutex for Active Process Locks.
+ *  - Generate process cookie for user-more thread.
+ *  - Add security calls where necessary.
+ *  - KeInit/StartThread for better isolation of code
  */
 
 /* INCLUDES ****************************************************************/
 extern LIST_ENTRY PsActiveProcessHead;
 extern PEPROCESS PsIdleProcess;
 extern PVOID PspSystemDllEntryPoint;
+extern PVOID PspSystemDllBase;
 extern PHANDLE_TABLE PspCidTable;
-
+extern BOOLEAN CcPfEnablePrefetcher;
+extern ULONG MmReadClusterSize;
 POBJECT_TYPE PsThreadType = NULL;
 
 /* FUNCTIONS ***************************************************************/
 
 VOID
-STDCALL
-PspThreadSpecialApc(PKAPC Apc,
-                    PKNORMAL_ROUTINE* NormalRoutine,
-                    PVOID* NormalContext,
-                    PVOID* SystemArgument1,
-                    PVOID* SystemArgument2)
-{
-    ExFreePool(Apc);
-}
-
-VOID
-STDCALL
+NTAPI
 PspUserThreadStartup(PKSTART_ROUTINE StartRoutine,
                      PVOID StartContext)
 {
-    PKAPC ThreadApc;
-    PETHREAD Thread = PsGetCurrentThread();
+    PETHREAD Thread;
+    PTEB Teb;
+    BOOLEAN DeadThread = FALSE;
+    PAGED_CODE();
 
-    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);
+    /* Go to Passive Level */
+    KeLowerIrql(PASSIVE_LEVEL);
+    Thread = PsGetCurrentThread();
 
-    if (!Thread->Terminated) {
+    /* Check if the thread is dead */
+    if (Thread->DeadThread)
+    {
+        /* Remember that we're dead */
+        DPRINT1("This thread is already dead\n");
+        DeadThread = TRUE;
+}
+    else
+    {
+        /* Get the Locale ID and save Preferred Proc */
+        Teb =  NtCurrentTeb(); /* FIXME: This returns KPCR!!! */
+        //Teb->CurrentLocale = MmGetSessionLocaleId();
+        //Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
+    }
 
-        /* Allocate the APC */
-        ThreadApc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('T', 'h', 'r','d'));
+    /* Check if this is a system thread, or if we're hiding */
+    if ((Thread->SystemThread) || (Thread->HideFromDebugger))
+{
+        /* Notify the debugger */
+        DbgkCreateThread(StartContext);
+    }
 
-        /* Initialize it */
-        KeInitializeApc(ThreadApc,
-                        &Thread->Tcb,
-                        OriginalApcEnvironment,
-                        PspThreadSpecialApc,
+    /* Make sure we're not already dead */
+    if (!DeadThread)
+    {
+        /* Check if the Prefetcher is enabled */
+        if (CcPfEnablePrefetcher)
+        {
+            /* FIXME: Prepare to prefetch this process */
+        }
+
+        /* Raise to APC */
+        KfRaiseIrql(APC_LEVEL);
+
+        /* Queue the User APC */
+        KiInitializeUserApc(NULL,
+                            (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
+                            sizeof(KTRAP_FRAME) -
+                            sizeof(FX_SAVE_AREA)),
+                            PspSystemDllEntryPoint,
                         NULL,
-                        PspSystemDllEntryPoint,
-                        UserMode,
+                            PspSystemDllBase,
                         NULL);
 
-        /* Insert it into the queue */
-        KeInsertQueueApc(ThreadApc, NULL, NULL, IO_NO_INCREMENT);
-        Thread->Tcb.ApcState.UserApcPending = TRUE;
+        /* Lower it back to passive */
+        KeLowerIrql(PASSIVE_LEVEL);
+    }
+    else
+    {
+        /* We're dead, kill us now */
+        PspTerminateThreadByPointer(Thread, STATUS_THREAD_IS_TERMINATING, TRUE);
     }
 
-    /* Go to Passive Level and notify debugger */
-    KeLowerIrql(PASSIVE_LEVEL);
-    DbgkCreateThread(StartContext);
+    /* Do we have a cookie set yet? */
+    if (!SharedUserData->Cookie)
+    {
+        /* FIXME: Generate cookie */
+    }
 }
 
 VOID
-STDCALL
+NTAPI
 PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine,
                        PVOID StartContext)
 {
-    PETHREAD Thread = PsGetCurrentThread();
+    PETHREAD Thread;
 
     /* 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 */
+    if (!(Thread->Terminated) || !(Thread->DeadThread))
+    {
+        /* Call it the Start Routine */
+        StartRoutine(StartContext);
     }
 
     /* 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,
@@ -117,46 +158,54 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
     NTSTATUS Status;
     HANDLE_TABLE_ENTRY CidEntry;
     ULONG_PTR KernelStack;
+    PAGED_CODE();
 
-    /* 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 {
-
+    }
+    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))
+    {
         DPRINT1("Invalid Process Handle, or no handle given\n");
-        return(Status);
+        return Status;
+    }
+
+    /* Also make sure that User-Mode isn't trying to create a system thread */
+    if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
+    {
+        ObDereferenceObject(Process);
+        return STATUS_INVALID_HANDLE;
     }
 
     /* Create Thread Object */
-    DPRINT("Creating Thread Object\n");
     Status = ObCreateObject(PreviousMode,
                             PsThreadType,
                             ObjectAttributes,
@@ -166,69 +215,61 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
                             0,
                             0,
                             (PVOID*)&Thread);
-
-    /* Check for success */
-    if (!NT_SUCCESS(Status)) {
-
-        /* Dereference the Process */
+    if (!NT_SUCCESS(Status))
+    {
+        /* We failed; dereference the process and exit */
         DPRINT1("Failed to Create Thread Object\n");
         ObDereferenceObject(Process);
-        return(Status);
+        return Status;
     }
 
     /* Zero the Object entirely */
-    DPRINT("Cleaning Thread Object\n");
     RtlZeroMemory(Thread, sizeof(ETHREAD));
 
+    /* Set the Process CID */
+    Thread->ThreadsProcess = Process;
+    Thread->Cid.UniqueProcess = Process->UniqueProcessId;
+
     /* Create Cid Handle */
-    DPRINT("Creating Thread Handle (CID)\n");
     CidEntry.Object = Thread;
     CidEntry.GrantedAccess = 0;
     Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
-    if (!Thread->Cid.UniqueThread) {
-
+    if (!Thread->Cid.UniqueThread)
+    {
+        /* We couldn't create the CID, dereference everything and fail */
         DPRINT1("Failed to create Thread Handle (CID)\n");
         ObDereferenceObject(Process);
         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, MAXLONG);
+
+    /* 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 = (ULONG_PTR)MmCreateKernelStack(FALSE) + KERNEL_STACK_SIZE;
 
-    /* Set the Process CID */
-    DPRINT("Initialliazing Thread PID and Parent Process\n");
-    Thread->Cid.UniqueProcess = Process->UniqueProcessId;
-    Thread->ThreadsProcess = Process;
-
     /* Now let the kernel initialize the context */
-    if (ThreadContext) {
-
-        /* User-mode Thread */
-
-        /* Create Teb */
-        DPRINT("Initialliazing Thread PEB\n");
+    if (ThreadContext)
+    {
+        /* User-mode Thread, create Teb */
         TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
 
         /* 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;
 
         /* Let the kernel intialize the Thread */
-        DPRINT("Initialliazing Kernel Thread\n");
         KeInitializeThread(&Process->Pcb,
                            &Thread->Tcb,
                            PspUserThreadStartup,
@@ -237,16 +278,14 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
                            ThreadContext,
                            TebBase,
                            (PVOID)KernelStack);
-
-    } else {
-
+    }
+    else
+    {
         /* System Thread */
-        DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine);
         Thread->StartAddress = StartRoutine;
-        Thread->SystemThread = TRUE;
+        InterlockedOr(&Thread->CrossThreadFlags, 0x10);
 
         /* Let the kernel intialize the Thread */
-        DPRINT("Initialliazing Kernel Thread\n");
         KeInitializeThread(&Process->Pcb,
                            &Thread->Tcb,
                            PspSystemThreadStartup,
@@ -262,61 +301,63 @@ 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++;
+
+    /* Notify WMI */
+    //WmiTraceProcess(Process, TRUE);
+    //WmiTraceThread(Thread, InitialTeb, TRUE);
 
     /* Notify Thread Creation */
-    DPRINT("Running Thread Notify \n");
     PspRunCreateThreadNotifyRoutines(Thread, TRUE);
 
     /* Suspend the Thread if we have to */
-    if (CreateSuspended) {
-
-        DPRINT("Suspending Thread\n");
+    if (CreateSuspended)
+    {
         KeSuspendThread(&Thread->Tcb);
     }
 
+    /* Check if we were already terminated */
+    if (Thread->Terminated)
+    {
+        /* Force us to wake up to terminate */
+        KeForceResumeThread(&Thread->Tcb);
+    }
+
     /* Reference ourselves as a keep-alive */
     ObReferenceObject(Thread);
 
     /* Insert the Thread into the Object Manager */
-    DPRINT("Inserting Thread\n");
     Status = ObInsertObject((PVOID)Thread,
                             NULL,
                             DesiredAccess,
                             0,
                             NULL,
                             &hThread);
-
-    /* Return Cid and Handle */
-    DPRINT("All worked great!\n");
-    if(NT_SUCCESS(Status)) {
-
-        _SEH_TRY {
-
-            if(ClientId != NULL) {
-
-                *ClientId = Thread->Cid;
-            }
+    if(NT_SUCCESS(Status))
+    {
+        /* Wrap in SEH to protect against bad user-mode pointers */
+        _SEH_TRY
+        {
+            /* Return Cid and Handle */
+            if(ClientId) *ClientId = Thread->Cid;
             *ThreadHandle = hThread;
-
-        } _SEH_HANDLE {
-
+        }
+        _SEH_HANDLE
+        {
             Status = _SEH_GetExceptionCode();
-
-        _SEH_END;
+        }
+        _SEH_END;
     }
 
     /* FIXME: SECURITY */
 
     /* Dispatch thread */
-    DPRINT("About to dispatch the thread: %x!\n", &Thread->Tcb);
     OldIrql = KeAcquireDispatcherDatabaseLock ();
     KiUnblockThread(&Thread->Tcb, NULL, 0);
     KeReleaseDispatcherDatabaseLock(OldIrql);
 
     /* Return */
-    DPRINT("Returning\n");
     return Status;
 }
 
@@ -324,7 +365,7 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsCreateSystemThread(PHANDLE ThreadHandle,
                      ACCESS_MASK DesiredAccess,
                      POBJECT_ATTRIBUTES ObjectAttributes,
@@ -335,10 +376,11 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
 {
     PEPROCESS TargetProcess = NULL;
     HANDLE Handle = ProcessHandle;
+    PAGED_CODE();
 
     /* Check if we have a handle. If not, use the System Process */
-    if (!ProcessHandle) {
-
+    if (!ProcessHandle)
+    {
         Handle = NULL;
         TargetProcess = PsInitialSystemProcess;
     }
@@ -361,7 +403,7 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 PsLookupThreadByThreadId(IN HANDLE ThreadId,
                          OUT PETHREAD *Thread)
 {
@@ -369,7 +411,6 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId,
     PETHREAD FoundThread;
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
     PAGED_CODE();
-    
     KeEnterCriticalRegion();
 
     /* Get the CID Handle Entry */
@@ -392,9 +433,8 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId,
         ExUnlockHandleTableEntry(PspCidTable, CidEntry);
     }
     
-    KeLeaveCriticalRegion();
-
     /* Return to caller */
+    KeLeaveCriticalRegion();
     return Status;
 }
 
@@ -402,7 +442,7 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId,
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetCurrentThreadId(VOID)
 {
     return(PsGetCurrentThread()->Cid.UniqueThread);
@@ -412,7 +452,7 @@ PsGetCurrentThreadId(VOID)
  * @implemented
  */
 ULONG
-STDCALL
+NTAPI
 PsGetThreadFreezeCount(PETHREAD Thread)
 {
     return Thread->Tcb.FreezeCount;
@@ -422,7 +462,7 @@ PsGetThreadFreezeCount(PETHREAD Thread)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 PsGetThreadHardErrorsAreDisabled(PETHREAD Thread)
 {
     return Thread->HardErrorsAreDisabled;
@@ -432,7 +472,7 @@ PsGetThreadHardErrorsAreDisabled(PETHREAD Thread)
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetThreadId(PETHREAD Thread)
 {
     return Thread->Cid.UniqueThread;
@@ -442,7 +482,7 @@ PsGetThreadId(PETHREAD Thread)
  * @implemented
  */
 PEPROCESS
-STDCALL
+NTAPI
 PsGetThreadProcess(PETHREAD Thread)
 {
     return Thread->ThreadsProcess;
@@ -452,7 +492,7 @@ PsGetThreadProcess(PETHREAD Thread)
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetThreadProcessId(PETHREAD Thread)
 {
     return Thread->Cid.UniqueProcess;
@@ -462,7 +502,7 @@ PsGetThreadProcessId(PETHREAD Thread)
  * @implemented
  */
 HANDLE
-STDCALL
+NTAPI
 PsGetThreadSessionId(PETHREAD Thread)
 {
     return (HANDLE)Thread->ThreadsProcess->Session;
@@ -472,7 +512,7 @@ PsGetThreadSessionId(PETHREAD Thread)
  * @implemented
  */
 PTEB
-STDCALL
+NTAPI
 PsGetThreadTeb(PETHREAD Thread)
 {
     return Thread->Tcb.Teb;
@@ -482,7 +522,7 @@ PsGetThreadTeb(PETHREAD Thread)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetThreadWin32Thread(PETHREAD Thread)
 {
     return Thread->Tcb.Win32Thread;
@@ -492,7 +532,7 @@ PsGetThreadWin32Thread(PETHREAD Thread)
  * @implemented
  */
 KPROCESSOR_MODE
-STDCALL
+NTAPI
 PsGetCurrentThreadPreviousMode(VOID)
 {
     return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
@@ -502,7 +542,7 @@ PsGetCurrentThreadPreviousMode(VOID)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetCurrentThreadStackBase(VOID)
 {
     return PsGetCurrentThread()->Tcb.StackBase;
@@ -512,7 +552,7 @@ PsGetCurrentThreadStackBase(VOID)
  * @implemented
  */
 PVOID
-STDCALL
+NTAPI
 PsGetCurrentThreadStackLimit(VOID)
 {
     return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
@@ -522,7 +562,7 @@ PsGetCurrentThreadStackLimit(VOID)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 PsIsThreadTerminating(IN PETHREAD Thread)
 {
     return (Thread->Terminated ? TRUE : FALSE);
@@ -532,7 +572,7 @@ PsIsThreadTerminating(IN PETHREAD Thread)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 PsIsSystemThread(PETHREAD Thread)
 {
     return (Thread->SystemThread ? TRUE: FALSE);
@@ -542,7 +582,7 @@ PsIsSystemThread(PETHREAD Thread)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 PsIsThreadImpersonating(PETHREAD Thread)
 {
     return Thread->ActiveImpersonationInfo;
@@ -552,7 +592,7 @@ PsIsThreadImpersonating(PETHREAD Thread)
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 PsSetThreadHardErrorsAreDisabled(PETHREAD Thread,
                                  BOOLEAN HardErrorsAreDisabled)
 {
@@ -563,7 +603,7 @@ PsSetThreadHardErrorsAreDisabled(PETHREAD Thread,
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 PsSetThreadWin32Thread(PETHREAD Thread,
                        PVOID Win32Thread)
 {
@@ -571,7 +611,7 @@ PsSetThreadWin32Thread(PETHREAD Thread,
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtCreateThread(OUT PHANDLE ThreadHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
@@ -582,55 +622,53 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
                IN BOOLEAN CreateSuspended)
 {
     INITIAL_TEB SafeInitialTeb;
-    CONTEXT SafeContext;
     NTSTATUS Status = STATUS_SUCCESS;
-
     PAGED_CODE();
 
-    DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
-            ThreadHandle,ThreadContext);
-
-    if(KeGetPreviousMode() != KernelMode) {
-
-        if (ThreadContext == NULL) {
+    /* Check if this was from user-mode */
+    if(KeGetPreviousMode() != KernelMode)
+    {
+        /* Make sure that we got a context */
+        if (!ThreadContext)
+        {
             DPRINT1("No context for User-Mode Thread!!\n");
             return STATUS_INVALID_PARAMETER;
         }
 
-        _SEH_TRY {
-
+        /* Protect checks */
+        _SEH_TRY
+        {
+            /* Make sure the handle pointer we got is valid */
             ProbeForWriteHandle(ThreadHandle);
 
-            if(ClientId != NULL) {
-
-                ProbeForWrite(ClientId,
-                              sizeof(CLIENT_ID),
-                              sizeof(ULONG));
+            /* Check if the caller wants a client id */
+            if(ClientId)
+            {
+                /* Make sure we can write to it */
+                ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
             }
 
-            if(ThreadContext != NULL) {
-
-                ProbeForRead(ThreadContext,
-                             sizeof(CONTEXT),
-                             sizeof(ULONG));
-                SafeContext = *ThreadContext;
-                ThreadContext = &SafeContext;
-            }
+            /* Make sure that the entire context is readable */
+            ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
 
-            ProbeForRead(InitialTeb,
-                         sizeof(INITIAL_TEB),
-                         sizeof(ULONG));
+            /* Check the Initial TEB */
+            ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
             SafeInitialTeb = *InitialTeb;
-            InitialTeb = &SafeInitialTeb;
-
-        } _SEH_HANDLE {
-
+            }
+        _SEH_HANDLE
+        {
             Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
 
-        } _SEH_END;
-
+        /* Handle any failures in our SEH checks */
         if (!NT_SUCCESS(Status)) return Status;
     }
+    else
+    {
+        /* Use the Initial TEB as is */
+        SafeInitialTeb = *InitialTeb;
+    }
 
     /* Call the shared function */
     return PspCreateThread(ThreadHandle,
@@ -640,7 +678,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
                            NULL,
                            ClientId,
                            ThreadContext,
-                           InitialTeb,
+                           &SafeInitialTeb,
                            CreateSuspended,
                            NULL,
                            NULL);
@@ -650,7 +688,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
  * @implemented
  */
 NTSTATUS
-STDCALL
+NTAPI
 NtOpenThread(OUT PHANDLE ThreadHandle,
              IN ACCESS_MASK DesiredAccess,
              IN POBJECT_ATTRIBUTES ObjectAttributes,
@@ -724,19 +762,14 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
                                     DesiredAccess,
                                     NULL,
                                     &hThread);
-
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Could not open object by name\n");
+        if (!NT_SUCCESS(Status)) DPRINT1("Could not open object by name\n");
         }
-    }
     else if (ClientId != NULL)
     {
         /* Open by Thread ID */
         if (ClientId->UniqueProcess)
         {
             /* Get the Process */
-            DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess);
             Status = PsLookupProcessThreadByCid(ClientId,
                                                 NULL,
                                                 &Thread);
@@ -744,7 +777,6 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
         else
         {
             /* Get the Process */
-            DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread);
             Status = PsLookupThreadByThreadId(ClientId->UniqueThread,
                                               &Thread);
         }
@@ -777,11 +809,13 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
         return STATUS_INVALID_PARAMETER_MIX;
     }
 
-    /* Write back the handle */
+    /* Check for success */
     if(NT_SUCCESS(Status))
     {
+        /* Protect against bad user-mode pointers */
         _SEH_TRY
         {
+            /* Write back the handle */
             *ThreadHandle = hThread;
         }
         _SEH_HANDLE
@@ -796,7 +830,7 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtYieldExecution(VOID)
 {
     KiDispatchThread(Ready);
@@ -804,7 +838,7 @@ NtYieldExecution(VOID)
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtTestAlert(VOID)
 {
     /* Check and Alert Thread if needed */
@@ -815,7 +849,7 @@ NtTestAlert(VOID)
  * @implemented
  */
 KPROCESSOR_MODE
-STDCALL
+NTAPI
 ExGetPreviousMode (VOID)
 {
     return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
index f974e42..75824c3 100644 (file)
@@ -16,8 +16,8 @@
 
 /* GLOBALS ******************************************************************/
 
-static PKWIN32_PROCESS_CALLOUT PspWin32ProcessCallback = NULL;
-static PKWIN32_THREAD_CALLOUT PspWin32ThreadCallback = NULL;
+PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout = NULL;
+PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL;
 extern PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse;
 extern PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete;
 extern PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete;
@@ -53,8 +53,8 @@ VOID
 STDCALL
 PsEstablishWin32Callouts(PWIN32_CALLOUTS_FPNS CalloutData)
 {
-    PspWin32ProcessCallback = CalloutData->ProcessCallout;
-    PspWin32ThreadCallback = CalloutData->ThreadCallout;
+    PspW32ProcessCallout = CalloutData->ProcessCallout;
+    PspW32ThreadCallout = CalloutData->ThreadCallout;
     ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure;
     ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure;
     ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure;
@@ -79,7 +79,7 @@ PsConvertToGuiThread(VOID)
     }
 
     /* Make sure win32k is here */
-    if (!PspWin32ProcessCallback)
+    if (!PspW32ProcessCallout)
     {
         DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n");
         return STATUS_ACCESS_DENIED;
@@ -122,7 +122,7 @@ PsConvertToGuiThread(VOID)
     if (!Process->Win32Process)
     {
         /* Now tell win32k about us */
-        Status = PspWin32ProcessCallback(Process, TRUE);
+        Status = PspW32ProcessCallout(Process, TRUE);
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Danger: Win32k wasn't happy about us!\n");
@@ -135,7 +135,7 @@ PsConvertToGuiThread(VOID)
     ASSERT(Thread->Tcb.Win32Thread == 0);
 
     /* Tell Win32k about our thread */
-    Status = PspWin32ThreadCallback(Thread, PsW32ThreadCalloutInitialize);
+    Status = PspW32ThreadCallout(Thread, PsW32ThreadCalloutInitialize);
     if (!NT_SUCCESS(Status))
     {
         /* Revert our table */
@@ -147,39 +147,6 @@ PsConvertToGuiThread(VOID)
     return Status;
 }
 
-VOID
-NTAPI
-PsTerminateWin32Process (PEPROCESS Process)
-{
-  if (Process->Win32Process == NULL)
-    return;
-
-  if (PspWin32ProcessCallback != NULL)
-    {
-      PspWin32ProcessCallback (Process, FALSE);
-    }
-
-  /* don't delete the W32PROCESS structure at this point, wait until the
-     EPROCESS structure is being freed */
-}
-
-
-VOID
-NTAPI
-PsTerminateWin32Thread (PETHREAD Thread)
-{
-  if (Thread->Tcb.Win32Thread != NULL)
-  {
-    if (PspWin32ThreadCallback != NULL)
-    {
-      PspWin32ThreadCallback (Thread, PsW32ThreadCalloutExit);
-    }
-
-    /* don't delete the W32THREAD structure at this point, wait until the
-       ETHREAD structure is being freed */
-  }
-}
-
 NTSTATUS
 STDCALL
 NtW32Call(IN ULONG RoutineIndex,
index 9455418..2cfca0d 100644 (file)
 #include <ntoskrnl.h>
 #include <internal/debug.h>
 
+/* INTERNAL *****************************************************************/
+
+BOOLEAN
+NTAPI
+SeDetailedAuditingWithToken(IN PTOKEN Token)
+{
+    /* FIXME */
+    return FALSE;
+}
+
+VOID
+NTAPI
+SeAuditProcessExit(IN PEPROCESS Process)
+{
+    /* FIXME */
+}
 
 /* FUNCTIONS ****************************************************************/