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 PsInitialSystemProcess
= NULL
;
20 PEPROCESS PsIdleProcess
= NULL
;
21 POBJECT_TYPE PsProcessType
= NULL
;
22 extern PHANDLE_TABLE PspCidTable
;
24 EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock
;
26 LIST_ENTRY PsActiveProcessHead
;
27 FAST_MUTEX PspActiveProcessMutex
;
28 LARGE_INTEGER ShortPsLockDelay
, PsLockTimeout
;
30 /* INTERNAL FUNCTIONS *****************************************************************/
34 PsLockProcess(PEPROCESS Process
, BOOLEAN Timeout
)
37 PKTHREAD PrevLockOwner
;
38 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
39 PLARGE_INTEGER Delay
= (Timeout
? &PsLockTimeout
: NULL
);
40 PKTHREAD CallingThread
= KeGetCurrentThread();
44 KeEnterCriticalRegion();
48 PrevLockOwner
= (PKTHREAD
)InterlockedCompareExchangePointer(
49 &Process
->LockOwner
, CallingThread
, NULL
);
50 if(PrevLockOwner
== NULL
|| PrevLockOwner
== CallingThread
)
52 /* we got the lock or already locked it */
53 if(InterlockedIncrementUL(&Process
->LockCount
) == 1)
55 KeClearEvent(&Process
->LockEvent
);
58 return STATUS_SUCCESS
;
64 Status
= KeWaitForSingleObject(&Process
->LockEvent
,
69 if(!NT_SUCCESS(Status
) || Status
== STATUS_TIMEOUT
)
72 if(Status
== STATUS_TIMEOUT
)
74 DPRINT1("PsLockProcess(0x%x) timed out!\n", Process
);
77 KeLeaveCriticalRegion();
83 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
93 PsUnlockProcess(PEPROCESS Process
)
97 ASSERT(Process
->LockOwner
== KeGetCurrentThread());
99 if(InterlockedDecrementUL(&Process
->LockCount
) == 0)
101 InterlockedExchangePointer(&Process
->LockOwner
, NULL
);
102 KeSetEvent(&Process
->LockEvent
, IO_NO_INCREMENT
, FALSE
);
105 KeLeaveCriticalRegion();
110 PsGetNextProcess(PEPROCESS OldProcess
)
112 PEPROCESS NextProcess
;
115 /* Check if we have a previous process */
116 if (OldProcess
== NULL
)
118 /* We don't, start with the Idle Process */
119 Status
= ObReferenceObjectByPointer(PsIdleProcess
,
123 if (!NT_SUCCESS(Status
))
125 DPRINT1("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsIdleProcess\n");
129 return PsIdleProcess
;
132 /* Acquire the Active Process Lock */
133 ExAcquireFastMutex(&PspActiveProcessMutex
);
135 /* Start at the previous process */
136 NextProcess
= OldProcess
;
138 /* Loop until we fail */
141 /* Get the Process Link */
142 PLIST_ENTRY Flink
= (NextProcess
== PsIdleProcess
? PsActiveProcessHead
.Flink
:
143 NextProcess
->ActiveProcessLinks
.Flink
);
145 /* Move to the next Process if we're not back at the beginning */
146 if (Flink
!= &PsActiveProcessHead
)
148 NextProcess
= CONTAINING_RECORD(Flink
, EPROCESS
, ActiveProcessLinks
);
156 /* Reference the Process */
157 Status
= ObReferenceObjectByPointer(NextProcess
,
162 /* Exit the loop if the reference worked, keep going if there's an error */
163 if (NT_SUCCESS(Status
)) break;
166 /* Release the lock */
167 ExReleaseFastMutex(&PspActiveProcessMutex
);
169 /* Reference the Process we had referenced earlier */
170 ObDereferenceObject(OldProcess
);
176 PspCreateProcess(OUT PHANDLE ProcessHandle
,
177 IN ACCESS_MASK DesiredAccess
,
178 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
179 IN HANDLE ParentProcess OPTIONAL
,
180 IN BOOLEAN InheritObjectTable
,
181 IN HANDLE SectionHandle OPTIONAL
,
182 IN HANDLE DebugPort OPTIONAL
,
183 IN HANDLE ExceptionPort OPTIONAL
)
186 PEPROCESS Process
= NULL
;
187 PEPROCESS pParentProcess
= NULL
;
188 PEPORT pDebugPort
= NULL
;
189 PEPORT pExceptionPort
= NULL
;
190 PSECTION_OBJECT SectionObject
= NULL
;
191 NTSTATUS Status
= STATUS_SUCCESS
;
192 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
193 PHYSICAL_ADDRESS DirectoryTableBase
;
195 HANDLE_TABLE_ENTRY CidEntry
;
196 BOOLEAN ProcessCreated
= FALSE
;
198 DirectoryTableBase
.QuadPart
= (ULONGLONG
)0;
200 DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes
);
202 /* Reference the Parent if there is one */
203 if(ParentProcess
!= NULL
)
205 Status
= ObReferenceObjectByHandle(ParentProcess
,
206 PROCESS_CREATE_PROCESS
,
209 (PVOID
*)&pParentProcess
,
212 if (!NT_SUCCESS(Status
))
214 DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status
);
218 /* Inherit Parent process's Affinity. */
219 Affinity
= pParentProcess
->Pcb
.Affinity
;
224 pParentProcess
= NULL
;
227 * Only the boot cpu is initialized in the early boot phase.
229 Affinity
= 0xffffffff;
231 Affinity
= KeActiveProcessors
;
235 /* Add the debug port */
236 if (DebugPort
!= NULL
)
238 Status
= ObReferenceObjectByHandle(DebugPort
,
244 if (!NT_SUCCESS(Status
))
246 DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status
);
251 /* Add the exception port */
252 if (ExceptionPort
!= NULL
)
254 Status
= ObReferenceObjectByHandle(ExceptionPort
,
258 (PVOID
*)&pExceptionPort
,
261 if (!NT_SUCCESS(Status
))
263 DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status
);
268 /* Add the Section */
269 if (SectionHandle
!= NULL
)
271 Status
= ObReferenceObjectByHandle(SectionHandle
,
275 (PVOID
*)&SectionObject
,
277 if (!NT_SUCCESS(Status
))
279 DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status
);
284 /* Create the Object */
285 DPRINT("Creating Process Object\n");
286 Status
= ObCreateObject(PreviousMode
,
296 if (!NT_SUCCESS(Status
))
298 DPRINT1("Failed to create process object, Status: 0x%x\n", Status
);
302 /* Clean up the Object */
303 DPRINT("Cleaning Process Object\n");
304 RtlZeroMemory(Process
, sizeof(EPROCESS
));
306 /* Inherit stuff from the Parent since we now have the object created */
309 Process
->InheritedFromUniqueProcessId
= pParentProcess
->UniqueProcessId
;
310 Process
->Session
= pParentProcess
->Session
;
313 /* Set up the Quota Block from the Parent */
314 PspInheritQuota(Process
, pParentProcess
);
316 /* FIXME: Set up Dos Device Map from the Parent
317 ObInheritDeviceMap(Parent, Process) */
319 /* Set the Process' LPC Ports */
320 Process
->DebugPort
= pDebugPort
;
321 Process
->ExceptionPort
= pExceptionPort
;
323 /* Setup the Lock Event */
324 DPRINT("Initialzing Process Lock\n");
325 KeInitializeEvent(&Process
->LockEvent
, SynchronizationEvent
, FALSE
);
327 /* Setup the Thread List Head */
328 DPRINT("Initialzing Process ThreadListHead\n");
329 InitializeListHead(&Process
->ThreadListHead
);
331 /* Create or Clone the Handle Table */
332 DPRINT("Initialzing Process Handle Table\n");
333 ObCreateHandleTable(pParentProcess
, InheritObjectTable
, Process
);
334 DPRINT("Handle Table: %x\n", Process
->ObjectTable
);
336 /* Set Process's Directory Base */
337 DPRINT("Initialzing Process Directory Base\n");
338 MmCopyMmInfo(pParentProcess
? pParentProcess
: PsInitialSystemProcess
,
340 &DirectoryTableBase
);
342 /* Now initialize the Kernel Process */
343 DPRINT("Initialzing Kernel Process\n");
344 KeInitializeProcess(&Process
->Pcb
,
345 PROCESS_PRIORITY_NORMAL
,
349 /* Duplicate Parent Token */
350 DPRINT("Initialzing Process Token\n");
351 Status
= PspInitializeProcessSecurity(Process
, pParentProcess
);
352 if (!NT_SUCCESS(Status
))
354 DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status
);
358 /* Create the Process' Address Space */
359 DPRINT("Initialzing Process Address Space\n");
360 Status
= MmCreateProcessAddressSpace(Process
, SectionObject
);
361 if (!NT_SUCCESS(Status
))
363 DPRINT1("Failed to create Address Space\n");
369 /* Map the System Dll */
370 DPRINT("Mapping System DLL\n");
371 PspMapSystemDll(Process
, NULL
);
374 /* Create a handle for the Process */
375 DPRINT("Initialzing Process CID Handle\n");
376 CidEntry
.u1
.Object
= Process
;
377 CidEntry
.u2
.GrantedAccess
= 0;
378 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
379 DPRINT("Created CID: %d\n", Process
->UniqueProcessId
);
380 if(!Process
->UniqueProcessId
)
382 DPRINT1("Failed to create CID handle\n");
383 Status
= STATUS_UNSUCCESSFUL
; /* FIXME - what error should we return? */
387 /* FIXME: Insert into Job Object */
389 /* Create PEB only for User-Mode Processes */
392 DPRINT("Creating PEB\n");
393 Status
= MmCreatePeb(Process
);
394 if (!NT_SUCCESS(Status
))
396 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
401 /* W00T! The process can now be activated */
402 DPRINT("Inserting into Active Process List\n");
403 ExAcquireFastMutex(&PspActiveProcessMutex
);
404 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
405 ExReleaseFastMutex(&PspActiveProcessMutex
);
407 ProcessCreated
= TRUE
;
409 /* FIXME: SeCreateAccessStateEx */
411 /* Insert the Process into the Object Directory */
412 DPRINT("Inserting Process Object\n");
413 Status
= ObInsertObject(Process
,
419 if (NT_SUCCESS(Status
))
421 /* Set the Creation Time */
422 KeQuerySystemTime(&Process
->CreateTime
);
424 DPRINT("Done. Returning handle: %x\n", hProcess
);
427 *ProcessHandle
= hProcess
;
431 Status
= _SEH_GetExceptionCode();
433 /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
439 if(pParentProcess
!= NULL
) ObDereferenceObject(pParentProcess
);
440 if(SectionObject
!= NULL
) ObDereferenceObject(SectionObject
);
443 if(pExceptionPort
!= NULL
) ObDereferenceObject(pExceptionPort
);
444 if(pDebugPort
!= NULL
) ObDereferenceObject(pDebugPort
);
445 if(Process
!= NULL
) ObDereferenceObject(Process
);
451 /* PUBLIC FUNCTIONS *****************************************************************/
458 PsCreateSystemProcess(PHANDLE ProcessHandle
,
459 ACCESS_MASK DesiredAccess
,
460 POBJECT_ATTRIBUTES ObjectAttributes
)
462 return PspCreateProcess(ProcessHandle
,
465 NULL
, /* no parent process */
477 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
478 OUT PEPROCESS
*Process
)
480 PHANDLE_TABLE_ENTRY CidEntry
;
481 PEPROCESS FoundProcess
;
482 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
485 KeEnterCriticalRegion();
487 /* Get the CID Handle Entry */
488 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
491 /* Get the Process */
492 FoundProcess
= CidEntry
->u1
.Object
;
494 /* Make sure it's really a process */
495 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
497 /* Reference and return it */
498 ObReferenceObject(FoundProcess
);
499 *Process
= FoundProcess
;
500 Status
= STATUS_SUCCESS
;
503 /* Unlock the Entry */
504 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
507 KeLeaveCriticalRegion();
509 /* Return to caller */
518 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
519 OUT PEPROCESS
*Process OPTIONAL
,
520 OUT PETHREAD
*Thread
)
522 PHANDLE_TABLE_ENTRY CidEntry
;
523 PETHREAD FoundThread
;
524 NTSTATUS Status
= STATUS_INVALID_CID
;
527 KeEnterCriticalRegion();
529 /* Get the CID Handle Entry */
530 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
533 /* Get the Process */
534 FoundThread
= CidEntry
->u1
.Object
;
536 /* Make sure it's really a thread and this process' */
537 if ((FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
) &&
538 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
540 /* Reference and return it */
541 ObReferenceObject(FoundThread
);
542 *Thread
= FoundThread
;
543 Status
= STATUS_SUCCESS
;
545 /* Check if we should return the Process too */
548 /* Return it and reference it */
549 *Process
= FoundThread
->ThreadsProcess
;
550 ObReferenceObject(*Process
);
554 /* Unlock the Entry */
555 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
558 KeLeaveCriticalRegion();
560 /* Return to caller */
565 * FUNCTION: Returns a pointer to the current process
570 IoGetCurrentProcess(VOID
)
572 if (PsGetCurrentThread() == NULL
||
573 PsGetCurrentThread()->Tcb
.ApcState
.Process
== NULL
)
575 return(PsInitialSystemProcess
);
579 return(PEPROCESS
)(PsGetCurrentThread()->Tcb
.ApcState
.Process
);
586 LARGE_INTEGER STDCALL
587 PsGetProcessExitTime(VOID
)
590 Li
.QuadPart
= PsGetCurrentProcess()->ExitTime
.QuadPart
;
599 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
601 return Process
->CreateTime
.QuadPart
;
609 PsGetProcessDebugPort(PEPROCESS Process
)
611 return Process
->DebugPort
;
619 PsGetProcessExitProcessCalled(PEPROCESS Process
)
621 return Process
->ProcessExiting
;
629 PsGetProcessExitStatus(PEPROCESS Process
)
631 return Process
->ExitStatus
;
639 PsGetProcessId(PEPROCESS Process
)
641 return (HANDLE
)Process
->UniqueProcessId
;
649 PsGetProcessImageFileName(PEPROCESS Process
)
651 return (LPSTR
)Process
->ImageFileName
;
659 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
661 return Process
->InheritedFromUniqueProcessId
;
669 PsGetProcessJob(PEPROCESS Process
)
679 PsGetProcessPeb(PEPROCESS Process
)
689 PsGetProcessPriorityClass(PEPROCESS Process
)
691 return Process
->PriorityClass
;
698 PsGetCurrentProcessId(VOID
)
700 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
708 PsGetCurrentProcessSessionId(VOID
)
710 return PsGetCurrentProcess()->Session
;
718 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
720 return Process
->SectionBaseAddress
;
728 PsGetProcessSecurityPort(PEPROCESS Process
)
730 return Process
->SecurityPort
;
738 PsGetProcessSessionId(PEPROCESS Process
)
740 return (HANDLE
)Process
->Session
;
745 PsGetWin32Thread(VOID
)
747 return(PsGetCurrentThread()->Tcb
.Win32Thread
);
752 PsGetWin32Process(VOID
)
754 return (struct _W32PROCESS
*)PsGetCurrentProcess()->Win32Process
;
762 PsGetProcessWin32Process(PEPROCESS Process
)
764 return Process
->Win32Process
;
772 PsGetProcessWin32WindowStation(PEPROCESS Process
)
774 return Process
->Win32WindowStation
;
782 PsIsProcessBeingDebugged(PEPROCESS Process
)
784 return FALSE
; //Process->IsProcessBeingDebugged;
792 PsSetProcessPriorityClass(PEPROCESS Process
,
795 Process
->PriorityClass
= PriorityClass
;
803 PsSetProcessSecurityPort(PEPROCESS Process
,
806 Process
->SecurityPort
= SecurityPort
;
814 PsSetProcessWin32Process(PEPROCESS Process
,
817 Process
->Win32Process
= Win32Process
;
825 PsSetProcessWindowStation(PEPROCESS Process
,
828 Process
->Win32WindowStation
= WindowStation
;
836 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
840 return STATUS_NOT_IMPLEMENTED
;
844 * FUNCTION: Creates a process.
846 * ProcessHandle (OUT) = Caller supplied storage for the resulting
848 * DesiredAccess = Specifies the allowed or desired access to the
849 * process can be a combination of
850 * STANDARD_RIGHTS_REQUIRED| ..
851 * ObjectAttribute = Initialized attributes for the object, contains
852 * the rootdirectory and the filename
853 * ParentProcess = Handle to the parent process.
854 * InheritObjectTable = Specifies to inherit the objects of the parent
856 * SectionHandle = Handle to a section object to back the image file
857 * DebugPort = Handle to a DebugPort if NULL the system default debug
859 * ExceptionPort = Handle to a exception port.
861 * This function maps to the win32 CreateProcess.
868 NtCreateProcess(OUT PHANDLE ProcessHandle
,
869 IN ACCESS_MASK DesiredAccess
,
870 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
871 IN HANDLE ParentProcess
,
872 IN BOOLEAN InheritObjectTable
,
873 IN HANDLE SectionHandle OPTIONAL
,
874 IN HANDLE DebugPort OPTIONAL
,
875 IN HANDLE ExceptionPort OPTIONAL
)
877 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
878 NTSTATUS Status
= STATUS_SUCCESS
;
882 /* Check parameters */
883 if(PreviousMode
!= KernelMode
)
887 ProbeForWriteHandle(ProcessHandle
);
891 Status
= _SEH_GetExceptionCode();
895 if(!NT_SUCCESS(Status
)) return Status
;
898 /* Make sure there's a parent process */
899 if(ParentProcess
== NULL
)
901 /* Can't create System Processes like this */
902 Status
= STATUS_INVALID_PARAMETER
;
906 /* Create a user Process */
907 Status
= PspCreateProcess(ProcessHandle
,
926 NtOpenProcess(OUT PHANDLE ProcessHandle
,
927 IN ACCESS_MASK DesiredAccess
,
928 IN POBJECT_ATTRIBUTES ObjectAttributes
,
929 IN PCLIENT_ID ClientId
)
931 KPROCESSOR_MODE PreviousMode
;
932 CLIENT_ID SafeClientId
;
933 ULONG Attributes
= 0;
935 BOOLEAN HasObjectName
= FALSE
;
936 PETHREAD Thread
= NULL
;
937 PEPROCESS Process
= NULL
;
938 NTSTATUS Status
= STATUS_SUCCESS
;
942 PreviousMode
= KeGetPreviousMode();
944 /* Probe the paraemeters */
945 if(PreviousMode
!= KernelMode
)
949 ProbeForWriteHandle(ProcessHandle
);
953 ProbeForRead(ClientId
,
957 SafeClientId
= *ClientId
;
958 ClientId
= &SafeClientId
;
961 /* just probe the object attributes structure, don't capture it
962 completely. This is done later if necessary */
963 ProbeForRead(ObjectAttributes
,
964 sizeof(OBJECT_ATTRIBUTES
),
966 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
967 Attributes
= ObjectAttributes
->Attributes
;
971 Status
= _SEH_GetExceptionCode();
975 if(!NT_SUCCESS(Status
)) return Status
;
979 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
980 Attributes
= ObjectAttributes
->Attributes
;
983 if (HasObjectName
&& ClientId
!= NULL
)
985 /* can't pass both, n object name and a client id */
986 return STATUS_INVALID_PARAMETER_MIX
;
989 /* Open by name if one was given */
990 DPRINT("Checking type\n");
994 DPRINT("Opening by name\n");
995 Status
= ObOpenObjectByName(ObjectAttributes
,
1003 if (!NT_SUCCESS(Status
))
1005 DPRINT1("Could not open object by name\n");
1008 else if (ClientId
!= NULL
)
1010 /* Open by Thread ID */
1011 if (ClientId
->UniqueThread
)
1013 /* Get the Process */
1014 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
1015 Status
= PsLookupProcessThreadByCid(ClientId
,
1021 /* Get the Process */
1022 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
);
1023 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1027 if(!NT_SUCCESS(Status
))
1029 DPRINT1("Failure to find process\n");
1033 /* Open the Process Object */
1034 Status
= ObOpenObjectByPointer(Process
,
1041 if(!NT_SUCCESS(Status
))
1043 DPRINT1("Failure to open process\n");
1046 /* Dereference the thread if we used it */
1047 if (Thread
) ObDereferenceObject(Thread
);
1049 /* Dereference the Process */
1050 ObDereferenceObject(Process
);
1054 /* neither an object name nor a client id was passed */
1055 return STATUS_INVALID_PARAMETER_MIX
;
1058 /* Write back the handle */
1059 if(NT_SUCCESS(Status
))
1063 *ProcessHandle
= hProcess
;
1067 Status
= _SEH_GetExceptionCode();