2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/process.c
5 * PURPOSE: Process managment
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@cwcom.net)
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ******************************************************************/
19 PEPROCESS EXPORTED PsInitialSystemProcess
= NULL
;
20 PEPROCESS PsIdleProcess
= NULL
;
21 POBJECT_TYPE EXPORTED PsProcessType
= NULL
;
23 LIST_ENTRY PsActiveProcessHead
;
24 FAST_MUTEX PspActiveProcessMutex
;
25 LARGE_INTEGER ShortPsLockDelay
, PsLockTimeout
;
27 /* INTERNAL FUNCTIONS *****************************************************************/
30 PsLockProcess(PEPROCESS Process
, BOOLEAN Timeout
)
33 PKTHREAD PrevLockOwner
;
34 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
35 PLARGE_INTEGER Delay
= (Timeout
? &PsLockTimeout
: NULL
);
36 PKTHREAD CallingThread
= KeGetCurrentThread();
40 KeEnterCriticalRegion();
44 PrevLockOwner
= (PKTHREAD
)InterlockedCompareExchangePointer(
45 &Process
->LockOwner
, CallingThread
, NULL
);
46 if(PrevLockOwner
== NULL
|| PrevLockOwner
== CallingThread
)
48 /* we got the lock or already locked it */
49 if(InterlockedIncrementUL(&Process
->LockCount
) == 1)
51 KeClearEvent(&Process
->LockEvent
);
54 return STATUS_SUCCESS
;
60 Status
= KeWaitForSingleObject(&Process
->LockEvent
,
65 if(!NT_SUCCESS(Status
) || Status
== STATUS_TIMEOUT
)
68 if(Status
== STATUS_TIMEOUT
)
70 DPRINT1("PsLockProcess(0x%x) timed out!\n", Process
);
73 KeLeaveCriticalRegion();
79 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
88 PsUnlockProcess(PEPROCESS Process
)
92 ASSERT(Process
->LockOwner
== KeGetCurrentThread());
94 if(InterlockedDecrementUL(&Process
->LockCount
) == 0)
96 InterlockedExchangePointer(&Process
->LockOwner
, NULL
);
97 KeSetEvent(&Process
->LockEvent
, IO_NO_INCREMENT
, FALSE
);
100 KeLeaveCriticalRegion();
105 PsGetNextProcess(PEPROCESS OldProcess
)
107 PEPROCESS NextProcess
;
110 /* Check if we have a previous process */
111 if (OldProcess
== NULL
)
113 /* We don't, start with the Idle Process */
114 Status
= ObReferenceObjectByPointer(PsIdleProcess
,
118 if (!NT_SUCCESS(Status
))
120 DPRINT1("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsIdleProcess\n");
124 return PsIdleProcess
;
127 /* Acquire the Active Process Lock */
128 ExAcquireFastMutex(&PspActiveProcessMutex
);
130 /* Start at the previous process */
131 NextProcess
= OldProcess
;
133 /* Loop until we fail */
136 /* Get the Process Link */
137 PLIST_ENTRY Flink
= (NextProcess
== PsIdleProcess
? PsActiveProcessHead
.Flink
:
138 NextProcess
->ActiveProcessLinks
.Flink
);
140 /* Move to the next Process if we're not back at the beginning */
141 if (Flink
!= &PsActiveProcessHead
)
143 NextProcess
= CONTAINING_RECORD(Flink
, EPROCESS
, ActiveProcessLinks
);
151 /* Reference the Process */
152 Status
= ObReferenceObjectByPointer(NextProcess
,
157 /* Exit the loop if the reference worked, keep going if there's an error */
158 if (NT_SUCCESS(Status
)) break;
161 /* Release the lock */
162 ExReleaseFastMutex(&PspActiveProcessMutex
);
164 /* Reference the Process we had referenced earlier */
165 ObDereferenceObject(OldProcess
);
171 PspCreateProcess(OUT PHANDLE ProcessHandle
,
172 IN ACCESS_MASK DesiredAccess
,
173 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
174 IN HANDLE ParentProcess OPTIONAL
,
175 IN BOOLEAN InheritObjectTable
,
176 IN HANDLE SectionHandle OPTIONAL
,
177 IN HANDLE DebugPort OPTIONAL
,
178 IN HANDLE ExceptionPort OPTIONAL
)
182 PEPROCESS pParentProcess
;
183 PEPORT pDebugPort
= NULL
;
184 PEPORT pExceptionPort
= NULL
;
185 PSECTION_OBJECT SectionObject
= NULL
;
186 NTSTATUS Status
= STATUS_SUCCESS
;
187 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
188 PHYSICAL_ADDRESS DirectoryTableBase
;
190 DirectoryTableBase
.QuadPart
= (ULONGLONG
)0;
192 DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes
);
194 /* Reference the Parent if there is one */
195 if(ParentProcess
!= NULL
)
197 Status
= ObReferenceObjectByHandle(ParentProcess
,
198 PROCESS_CREATE_PROCESS
,
201 (PVOID
*)&pParentProcess
,
204 if (!NT_SUCCESS(Status
))
206 DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status
);
210 /* Inherit Parent process's Affinity. */
211 Affinity
= pParentProcess
->Pcb
.Affinity
;
216 pParentProcess
= NULL
;
217 Affinity
= KeActiveProcessors
;
220 /* Add the debug port */
221 if (DebugPort
!= NULL
)
223 Status
= ObReferenceObjectByHandle(DebugPort
,
229 if (!NT_SUCCESS(Status
))
231 DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status
);
232 goto exitdereferenceobjects
;
236 /* Add the exception port */
237 if (ExceptionPort
!= NULL
)
239 Status
= ObReferenceObjectByHandle(ExceptionPort
,
243 (PVOID
*)&pExceptionPort
,
246 if (!NT_SUCCESS(Status
))
248 DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status
);
249 goto exitdereferenceobjects
;
253 /* Add the Section */
254 if (SectionHandle
!= NULL
)
256 Status
= ObReferenceObjectByHandle(SectionHandle
,
260 (PVOID
*)&SectionObject
,
262 if (!NT_SUCCESS(Status
))
264 DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status
);
265 goto exitdereferenceobjects
;
269 /* Create the Object */
270 DPRINT("Creating Process Object\n");
271 Status
= ObCreateObject(PreviousMode
,
281 if (!NT_SUCCESS(Status
))
283 DPRINT1("Failed to create process object, Status: 0x%x\n", Status
);
284 goto exitdereferenceobjects
;
287 /* Clean up the Object */
288 DPRINT("Cleaning Process Object\n");
289 RtlZeroMemory(Process
, sizeof(EPROCESS
));
291 /* Inherit stuff from the Parent since we now have the object created */
294 Process
->InheritedFromUniqueProcessId
= pParentProcess
->UniqueProcessId
;
295 Process
->Session
= pParentProcess
->Session
;
298 /* FIXME: Set up the Quota Block from the Parent
299 PspInheritQuota(Parent, Process); */
301 /* FIXME: Set up Dos Device Map from the Parent
302 ObInheritDeviceMap(Parent, Process) */
304 /* Set the Process' LPC Ports */
305 Process
->DebugPort
= pDebugPort
;
306 Process
->ExceptionPort
= pExceptionPort
;
308 /* Setup the Lock Event */
309 DPRINT("Initialzing Process Lock\n");
310 KeInitializeEvent(&Process
->LockEvent
, SynchronizationEvent
, FALSE
);
312 /* Setup the Thread List Head */
313 DPRINT("Initialzing Process ThreadListHead\n");
314 InitializeListHead(&Process
->ThreadListHead
);
316 /* Create or Clone the Handle Table */
317 DPRINT("Initialzing Process Handle Table\n");
318 ObCreateHandleTable(pParentProcess
, InheritObjectTable
, Process
);
319 DPRINT("Handle Table: %x\n", Process
->ObjectTable
);
321 /* Set Process's Directory Base */
322 DPRINT("Initialzing Process Directory Base\n");
323 MmCopyMmInfo(pParentProcess
? pParentProcess
: PsInitialSystemProcess
,
325 &DirectoryTableBase
);
327 /* Now initialize the Kernel Process */
328 DPRINT("Initialzing Kernel Process\n");
329 KeInitializeProcess(&Process
->Pcb
,
334 /* Duplicate Parent Token */
335 DPRINT("Initialzing Process Token\n");
336 Status
= PspInitializeProcessSecurity(Process
, pParentProcess
);
337 if (!NT_SUCCESS(Status
))
339 DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status
);
340 ObDereferenceObject(Process
);
341 goto exitdereferenceobjects
;
344 /* Create the Process' Address Space */
345 DPRINT("Initialzing Process Address Space\n");
346 Status
= MmCreateProcessAddressSpace(Process
, SectionObject
);
347 if (!NT_SUCCESS(Status
))
349 DPRINT1("Failed to create Address Space\n");
350 ObDereferenceObject(Process
);
351 goto exitdereferenceobjects
;
356 /* Map the System Dll */
357 DPRINT("Mapping System DLL\n");
358 LdrpMapSystemDll(Process
, NULL
);
361 /* Create a handle for the Process */
362 DPRINT("Initialzing Process CID Handle\n");
363 Status
= PsCreateCidHandle(Process
,
365 &Process
->UniqueProcessId
);
366 DPRINT("Created CID: %d\n", Process
->UniqueProcessId
);
367 if(!NT_SUCCESS(Status
))
369 DPRINT1("Failed to create CID handle (unique process ID)! Status: 0x%x\n", Status
);
370 ObDereferenceObject(Process
);
371 goto exitdereferenceobjects
;
374 /* FIXME: Insert into Job Object */
376 /* Create PEB only for User-Mode Processes */
379 DPRINT("Creating PEB\n");
380 Status
= MmCreatePeb(Process
);
381 if (!NT_SUCCESS(Status
))
383 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
384 ObDereferenceObject(Process
);
385 goto exitdereferenceobjects
;
388 /* Let's take advantage of this time to kill the reference too */
389 ObDereferenceObject(pParentProcess
);
390 pParentProcess
= NULL
;
393 /* W00T! The process can now be activated */
394 DPRINT("Inserting into Active Process List\n");
395 ExAcquireFastMutex(&PspActiveProcessMutex
);
396 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
397 ExReleaseFastMutex(&PspActiveProcessMutex
);
399 /* FIXME: SeCreateAccessStateEx */
401 /* Insert the Process into the Object Directory */
402 DPRINT("Inserting Process Object\n");
403 Status
= ObInsertObject(Process
,
409 if (!NT_SUCCESS(Status
))
411 DPRINT1("Could not get a handle to the Process Object\n");
412 ObDereferenceObject(Process
);
413 goto exitdereferenceobjects
;
416 /* Set the Creation Time */
417 KeQuerySystemTime(&Process
->CreateTime
);
419 DPRINT("Done. Returning handle: %x\n", hProcess
);
422 *ProcessHandle
= hProcess
;
426 Status
= _SEH_GetExceptionCode();
429 /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
432 ObDereferenceObject(Process
);
435 exitdereferenceobjects
:
436 if(SectionObject
!= NULL
) ObDereferenceObject(SectionObject
);
437 if(pExceptionPort
!= NULL
) ObDereferenceObject(pExceptionPort
);
438 if(pDebugPort
!= NULL
) ObDereferenceObject(pDebugPort
);
439 if(pParentProcess
!= NULL
) ObDereferenceObject(pParentProcess
);
443 /* PUBLIC FUNCTIONS *****************************************************************/
450 PsCreateSystemProcess(PHANDLE ProcessHandle
,
451 ACCESS_MASK DesiredAccess
,
452 POBJECT_ATTRIBUTES ObjectAttributes
)
454 return PspCreateProcess(ProcessHandle
,
457 NULL
, /* no parent process */
469 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
470 OUT PEPROCESS
*Process
)
472 PHANDLE_TABLE_ENTRY CidEntry
;
473 PEPROCESS FoundProcess
;
479 CidEntry
= PsLookupCidHandle(ProcessId
, PsProcessType
, (PVOID
*)&FoundProcess
);
482 ObReferenceObject(FoundProcess
);
484 PsUnlockCidHandle(CidEntry
);
486 *Process
= FoundProcess
;
487 return STATUS_SUCCESS
;
490 return STATUS_INVALID_PARAMETER
;
494 * FUNCTION: Returns a pointer to the current process
499 IoGetCurrentProcess(VOID
)
501 if (PsGetCurrentThread() == NULL
||
502 PsGetCurrentThread()->Tcb
.ApcState
.Process
== NULL
)
504 return(PsInitialSystemProcess
);
508 return(PEPROCESS
)(PsGetCurrentThread()->Tcb
.ApcState
.Process
);
515 LARGE_INTEGER STDCALL
516 PsGetProcessExitTime(VOID
)
519 Li
.QuadPart
= PsGetCurrentProcess()->ExitTime
.QuadPart
;
528 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
530 return Process
->CreateTime
.QuadPart
;
538 PsGetProcessDebugPort(PEPROCESS Process
)
540 return Process
->DebugPort
;
548 PsGetProcessExitProcessCalled(PEPROCESS Process
)
550 return Process
->ProcessExiting
;
558 PsGetProcessExitStatus(PEPROCESS Process
)
560 return Process
->ExitStatus
;
568 PsGetProcessId(PEPROCESS Process
)
570 return (HANDLE
)Process
->UniqueProcessId
;
578 PsGetProcessImageFileName(PEPROCESS Process
)
580 return (LPSTR
)Process
->ImageFileName
;
588 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
590 return Process
->InheritedFromUniqueProcessId
;
598 PsGetProcessJob(PEPROCESS Process
)
608 PsGetProcessPeb(PEPROCESS Process
)
618 PsGetProcessPriorityClass(PEPROCESS Process
)
620 return Process
->PriorityClass
;
627 PsGetCurrentProcessId(VOID
)
629 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
637 PsGetCurrentProcessSessionId(VOID
)
639 return PsGetCurrentProcess()->Session
;
647 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
649 return Process
->SectionBaseAddress
;
657 PsGetProcessSecurityPort(PEPROCESS Process
)
659 return Process
->SecurityPort
;
667 PsGetProcessSessionId(PEPROCESS Process
)
669 return (HANDLE
)Process
->Session
;
677 PsGetProcessWin32Process(PEPROCESS Process
)
679 return Process
->Win32Process
;
687 PsGetProcessWin32WindowStation(PEPROCESS Process
)
689 return Process
->Win32WindowStation
;
697 PsIsProcessBeingDebugged(PEPROCESS Process
)
699 return FALSE
; //Process->IsProcessBeingDebugged;
707 PsSetProcessPriorityClass(PEPROCESS Process
,
710 Process
->PriorityClass
= PriorityClass
;
718 PsSetProcessSecurityPort(PEPROCESS Process
,
721 Process
->SecurityPort
= SecurityPort
;
729 PsSetProcessWin32Process(PEPROCESS Process
,
732 Process
->Win32Process
= Win32Process
;
740 PsSetProcessWin32WindowStation(PEPROCESS Process
,
743 Process
->Win32WindowStation
= WindowStation
;
747 * FUNCTION: Creates a process.
749 * ProcessHandle (OUT) = Caller supplied storage for the resulting
751 * DesiredAccess = Specifies the allowed or desired access to the
752 * process can be a combination of
753 * STANDARD_RIGHTS_REQUIRED| ..
754 * ObjectAttribute = Initialized attributes for the object, contains
755 * the rootdirectory and the filename
756 * ParentProcess = Handle to the parent process.
757 * InheritObjectTable = Specifies to inherit the objects of the parent
759 * SectionHandle = Handle to a section object to back the image file
760 * DebugPort = Handle to a DebugPort if NULL the system default debug
762 * ExceptionPort = Handle to a exception port.
764 * This function maps to the win32 CreateProcess.
771 NtCreateProcess(OUT PHANDLE ProcessHandle
,
772 IN ACCESS_MASK DesiredAccess
,
773 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
774 IN HANDLE ParentProcess
,
775 IN BOOLEAN InheritObjectTable
,
776 IN HANDLE SectionHandle OPTIONAL
,
777 IN HANDLE DebugPort OPTIONAL
,
778 IN HANDLE ExceptionPort OPTIONAL
)
780 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
781 NTSTATUS Status
= STATUS_SUCCESS
;
785 /* Check parameters */
786 if(PreviousMode
!= KernelMode
)
790 ProbeForWrite(ProcessHandle
,
796 Status
= _SEH_GetExceptionCode();
800 if(!NT_SUCCESS(Status
)) return Status
;
803 /* Make sure there's a parent process */
804 if(ParentProcess
== NULL
)
806 /* Can't create System Processes like this */
807 Status
= STATUS_INVALID_PARAMETER
;
811 /* Create a user Process */
812 Status
= PspCreateProcess(ProcessHandle
,
831 NtOpenProcess(OUT PHANDLE ProcessHandle
,
832 IN ACCESS_MASK DesiredAccess
,
833 IN POBJECT_ATTRIBUTES ObjectAttributes
,
834 IN PCLIENT_ID ClientId
)
836 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
837 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
839 PETHREAD Thread
= NULL
;
841 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
842 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
843 ProcessHandle
, DesiredAccess
, ObjectAttributes
, ClientId
,
844 ClientId
->UniqueProcess
, ClientId
->UniqueThread
);
848 /* Open by name if one was given */
849 DPRINT("Checking type\n");
850 if (ObjectAttributes
->ObjectName
)
853 DPRINT("Opening by name\n");
854 Status
= ObOpenObjectByName(ObjectAttributes
,
862 if (Status
!= STATUS_SUCCESS
)
864 DPRINT1("Could not open object by name\n");
868 DPRINT("Found: %x\n", ProcessHandle
);
873 /* Open by Thread ID */
874 if (ClientId
->UniqueThread
)
876 /* Get the Process */
877 if (ClientId
->UniqueThread
== (HANDLE
)-1) KEBUGCHECK(0);
878 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
879 Status
= PsLookupProcessThreadByCid(ClientId
,
882 DPRINT("Found: %x\n", Process
);
886 /* Get the Process */
887 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
);
888 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
890 DPRINT("Found: %x\n", Process
);
893 if(!NT_SUCCESS(Status
))
895 DPRINT1("Failure to find process\n");
899 /* Open the Process Object */
900 Status
= ObOpenObjectByPointer(Process
,
901 ObjectAttributes
->Attributes
,
907 if(!NT_SUCCESS(Status
))
909 DPRINT1("Failure to open process\n");
912 /* Dereference the thread if we used it */
913 if (Thread
) ObDereferenceObject(Thread
);
915 /* Dereference the Process */
916 ObDereferenceObject(Process
);