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
;
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 DirectoryTableBase
.QuadPart
= (ULONGLONG
)0;
197 BOOLEAN ProcessCreated
= FALSE
;
199 DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes
);
201 /* Reference the Parent if there is one */
202 if(ParentProcess
!= NULL
)
204 Status
= ObReferenceObjectByHandle(ParentProcess
,
205 PROCESS_CREATE_PROCESS
,
208 (PVOID
*)&pParentProcess
,
211 if (!NT_SUCCESS(Status
))
213 DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status
);
217 /* Inherit Parent process's Affinity. */
218 Affinity
= pParentProcess
->Pcb
.Affinity
;
223 pParentProcess
= NULL
;
226 * Only the boot cpu is initialized in the early boot phase.
228 Affinity
= 0xffffffff;
230 Affinity
= KeActiveProcessors
;
234 /* Add the debug port */
235 if (DebugPort
!= NULL
)
237 Status
= ObReferenceObjectByHandle(DebugPort
,
243 if (!NT_SUCCESS(Status
))
245 DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status
);
250 /* Add the exception port */
251 if (ExceptionPort
!= NULL
)
253 Status
= ObReferenceObjectByHandle(ExceptionPort
,
257 (PVOID
*)&pExceptionPort
,
260 if (!NT_SUCCESS(Status
))
262 DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status
);
267 /* Add the Section */
268 if (SectionHandle
!= NULL
)
270 Status
= ObReferenceObjectByHandle(SectionHandle
,
274 (PVOID
*)&SectionObject
,
276 if (!NT_SUCCESS(Status
))
278 DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status
);
283 /* Create the Object */
284 DPRINT("Creating Process Object\n");
285 Status
= ObCreateObject(PreviousMode
,
295 if (!NT_SUCCESS(Status
))
297 DPRINT1("Failed to create process object, Status: 0x%x\n", Status
);
301 /* Clean up the Object */
302 DPRINT("Cleaning Process Object\n");
303 RtlZeroMemory(Process
, sizeof(EPROCESS
));
305 /* Inherit stuff from the Parent since we now have the object created */
308 Process
->InheritedFromUniqueProcessId
= pParentProcess
->UniqueProcessId
;
309 Process
->Session
= pParentProcess
->Session
;
312 /* Set up the Quota Block from the Parent */
313 PspInheritQuota(Process
, pParentProcess
);
315 /* FIXME: Set up Dos Device Map from the Parent
316 ObInheritDeviceMap(Parent, Process) */
318 /* Set the Process' LPC Ports */
319 Process
->DebugPort
= pDebugPort
;
320 Process
->ExceptionPort
= pExceptionPort
;
322 /* Setup the Lock Event */
323 DPRINT("Initialzing Process Lock\n");
324 KeInitializeEvent(&Process
->LockEvent
, SynchronizationEvent
, FALSE
);
326 /* Setup the Thread List Head */
327 DPRINT("Initialzing Process ThreadListHead\n");
328 InitializeListHead(&Process
->ThreadListHead
);
330 /* Create or Clone the Handle Table */
331 DPRINT("Initialzing Process Handle Table\n");
332 ObCreateHandleTable(pParentProcess
, InheritObjectTable
, Process
);
333 DPRINT("Handle Table: %x\n", Process
->ObjectTable
);
335 /* Set Process's Directory Base */
336 DPRINT("Initialzing Process Directory Base\n");
337 MmCopyMmInfo(pParentProcess
? pParentProcess
: PsInitialSystemProcess
,
339 &DirectoryTableBase
);
341 /* Now initialize the Kernel Process */
342 DPRINT("Initialzing Kernel Process\n");
343 KeInitializeProcess(&Process
->Pcb
,
344 PROCESS_PRIORITY_NORMAL
,
348 /* Duplicate Parent Token */
349 DPRINT("Initialzing Process Token\n");
350 Status
= PspInitializeProcessSecurity(Process
, pParentProcess
);
351 if (!NT_SUCCESS(Status
))
353 DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status
);
357 /* Create the Process' Address Space */
358 DPRINT("Initialzing Process Address Space\n");
359 Status
= MmCreateProcessAddressSpace(Process
, SectionObject
);
360 if (!NT_SUCCESS(Status
))
362 DPRINT1("Failed to create Address Space\n");
368 /* Map the System Dll */
369 DPRINT("Mapping System DLL\n");
370 PspMapSystemDll(Process
, NULL
);
373 /* Create a handle for the Process */
374 DPRINT("Initialzing Process CID Handle\n");
375 CidEntry
.u1
.Object
= Process
;
376 CidEntry
.u2
.GrantedAccess
= 0;
377 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
378 DPRINT("Created CID: %d\n", Process
->UniqueProcessId
);
379 if(!Process
->UniqueProcessId
)
381 DPRINT1("Failed to create CID handle\n");
382 Status
= STATUS_UNSUCCESSFUL
; /* FIXME - what error should we return? */
386 /* FIXME: Insert into Job Object */
388 /* Create PEB only for User-Mode Processes */
391 DPRINT("Creating PEB\n");
392 Status
= MmCreatePeb(Process
);
393 if (!NT_SUCCESS(Status
))
395 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
400 /* W00T! The process can now be activated */
401 DPRINT("Inserting into Active Process List\n");
402 ExAcquireFastMutex(&PspActiveProcessMutex
);
403 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
404 ExReleaseFastMutex(&PspActiveProcessMutex
);
406 ProcessCreated
= TRUE
;
408 /* FIXME: SeCreateAccessStateEx */
410 /* Insert the Process into the Object Directory */
411 DPRINT("Inserting Process Object\n");
412 Status
= ObInsertObject(Process
,
418 if (NT_SUCCESS(Status
))
420 /* Set the Creation Time */
421 KeQuerySystemTime(&Process
->CreateTime
);
423 DPRINT("Done. Returning handle: %x\n", hProcess
);
426 *ProcessHandle
= hProcess
;
430 Status
= _SEH_GetExceptionCode();
432 /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
438 if(pParentProcess
!= NULL
) ObDereferenceObject(pParentProcess
);
441 if(SectionObject
!= NULL
) ObDereferenceObject(SectionObject
);
442 if(pExceptionPort
!= NULL
) ObDereferenceObject(pExceptionPort
);
443 if(pDebugPort
!= NULL
) ObDereferenceObject(pDebugPort
);
444 if(Process
!= NULL
) ObDereferenceObject(Process
);
450 /* PUBLIC FUNCTIONS *****************************************************************/
457 PsCreateSystemProcess(PHANDLE ProcessHandle
,
458 ACCESS_MASK DesiredAccess
,
459 POBJECT_ATTRIBUTES ObjectAttributes
)
461 return PspCreateProcess(ProcessHandle
,
464 NULL
, /* no parent process */
476 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
477 OUT PEPROCESS
*Process
)
479 PHANDLE_TABLE_ENTRY CidEntry
;
480 PEPROCESS FoundProcess
;
481 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
484 KeEnterCriticalRegion();
486 /* Get the CID Handle Entry */
487 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
490 /* Get the Process */
491 FoundProcess
= CidEntry
->u1
.Object
;
493 /* Make sure it's really a process */
494 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
496 /* Reference and return it */
497 ObReferenceObject(FoundProcess
);
498 *Process
= FoundProcess
;
499 Status
= STATUS_SUCCESS
;
502 /* Unlock the Entry */
503 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
506 KeLeaveCriticalRegion();
508 /* Return to caller */
517 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
518 OUT PEPROCESS
*Process OPTIONAL
,
519 OUT PETHREAD
*Thread
)
521 PHANDLE_TABLE_ENTRY CidEntry
;
522 PETHREAD FoundThread
;
523 NTSTATUS Status
= STATUS_INVALID_CID
;
526 KeEnterCriticalRegion();
528 /* Get the CID Handle Entry */
529 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
532 /* Get the Process */
533 FoundThread
= CidEntry
->u1
.Object
;
535 /* Make sure it's really a thread and this process' */
536 if ((FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
) &&
537 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
539 /* Reference and return it */
540 ObReferenceObject(FoundThread
);
541 *Thread
= FoundThread
;
542 Status
= STATUS_SUCCESS
;
544 /* Check if we should return the Process too */
547 /* Return it and reference it */
548 *Process
= FoundThread
->ThreadsProcess
;
549 ObReferenceObject(*Process
);
553 /* Unlock the Entry */
554 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
557 KeLeaveCriticalRegion();
559 /* Return to caller */
564 * FUNCTION: Returns a pointer to the current process
569 IoGetCurrentProcess(VOID
)
571 if (PsGetCurrentThread() == NULL
||
572 PsGetCurrentThread()->Tcb
.ApcState
.Process
== NULL
)
574 return(PsInitialSystemProcess
);
578 return(PEPROCESS
)(PsGetCurrentThread()->Tcb
.ApcState
.Process
);
585 LARGE_INTEGER STDCALL
586 PsGetProcessExitTime(VOID
)
589 Li
.QuadPart
= PsGetCurrentProcess()->ExitTime
.QuadPart
;
598 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
600 return Process
->CreateTime
.QuadPart
;
608 PsGetProcessDebugPort(PEPROCESS Process
)
610 return Process
->DebugPort
;
618 PsGetProcessExitProcessCalled(PEPROCESS Process
)
620 return Process
->ProcessExiting
;
628 PsGetProcessExitStatus(PEPROCESS Process
)
630 return Process
->ExitStatus
;
638 PsGetProcessId(PEPROCESS Process
)
640 return (HANDLE
)Process
->UniqueProcessId
;
648 PsGetProcessImageFileName(PEPROCESS Process
)
650 return (LPSTR
)Process
->ImageFileName
;
658 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
660 return Process
->InheritedFromUniqueProcessId
;
668 PsGetProcessJob(PEPROCESS Process
)
678 PsGetProcessPeb(PEPROCESS Process
)
688 PsGetProcessPriorityClass(PEPROCESS Process
)
690 return Process
->PriorityClass
;
697 PsGetCurrentProcessId(VOID
)
699 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
707 PsGetCurrentProcessSessionId(VOID
)
709 return PsGetCurrentProcess()->Session
;
717 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
719 return Process
->SectionBaseAddress
;
727 PsGetProcessSecurityPort(PEPROCESS Process
)
729 return Process
->SecurityPort
;
737 PsGetProcessSessionId(PEPROCESS Process
)
739 return (HANDLE
)Process
->Session
;
744 PsGetWin32Thread(VOID
)
746 return(PsGetCurrentThread()->Tcb
.Win32Thread
);
751 PsGetWin32Process(VOID
)
753 return (struct _W32PROCESS
*)PsGetCurrentProcess()->Win32Process
;
761 PsGetProcessWin32Process(PEPROCESS Process
)
763 return Process
->Win32Process
;
771 PsGetProcessWin32WindowStation(PEPROCESS Process
)
773 return Process
->Win32WindowStation
;
781 PsIsProcessBeingDebugged(PEPROCESS Process
)
783 return FALSE
; //Process->IsProcessBeingDebugged;
791 PsSetProcessPriorityClass(PEPROCESS Process
,
794 Process
->PriorityClass
= PriorityClass
;
802 PsSetProcessSecurityPort(PEPROCESS Process
,
805 Process
->SecurityPort
= SecurityPort
;
813 PsSetProcessWin32Process(PEPROCESS Process
,
816 Process
->Win32Process
= Win32Process
;
824 PsSetProcessWindowStation(PEPROCESS Process
,
827 Process
->Win32WindowStation
= WindowStation
;
835 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
839 return STATUS_NOT_IMPLEMENTED
;
843 * FUNCTION: Creates a process.
845 * ProcessHandle (OUT) = Caller supplied storage for the resulting
847 * DesiredAccess = Specifies the allowed or desired access to the
848 * process can be a combination of
849 * STANDARD_RIGHTS_REQUIRED| ..
850 * ObjectAttribute = Initialized attributes for the object, contains
851 * the rootdirectory and the filename
852 * ParentProcess = Handle to the parent process.
853 * InheritObjectTable = Specifies to inherit the objects of the parent
855 * SectionHandle = Handle to a section object to back the image file
856 * DebugPort = Handle to a DebugPort if NULL the system default debug
858 * ExceptionPort = Handle to a exception port.
860 * This function maps to the win32 CreateProcess.
867 NtCreateProcess(OUT PHANDLE ProcessHandle
,
868 IN ACCESS_MASK DesiredAccess
,
869 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
870 IN HANDLE ParentProcess
,
871 IN BOOLEAN InheritObjectTable
,
872 IN HANDLE SectionHandle OPTIONAL
,
873 IN HANDLE DebugPort OPTIONAL
,
874 IN HANDLE ExceptionPort OPTIONAL
)
876 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
877 NTSTATUS Status
= STATUS_SUCCESS
;
881 /* Check parameters */
882 if(PreviousMode
!= KernelMode
)
886 ProbeForWriteHandle(ProcessHandle
);
890 Status
= _SEH_GetExceptionCode();
894 if(!NT_SUCCESS(Status
)) return Status
;
897 /* Make sure there's a parent process */
898 if(ParentProcess
== NULL
)
900 /* Can't create System Processes like this */
901 Status
= STATUS_INVALID_PARAMETER
;
905 /* Create a user Process */
906 Status
= PspCreateProcess(ProcessHandle
,
925 NtOpenProcess(OUT PHANDLE ProcessHandle
,
926 IN ACCESS_MASK DesiredAccess
,
927 IN POBJECT_ATTRIBUTES ObjectAttributes
,
928 IN PCLIENT_ID ClientId
)
930 KPROCESSOR_MODE PreviousMode
;
931 CLIENT_ID SafeClientId
;
932 ULONG Attributes
= 0;
934 BOOLEAN HasObjectName
= FALSE
;
935 PETHREAD Thread
= NULL
;
936 PEPROCESS Process
= NULL
;
937 NTSTATUS Status
= STATUS_SUCCESS
;
941 PreviousMode
= KeGetPreviousMode();
943 /* Probe the paraemeters */
944 if(PreviousMode
!= KernelMode
)
948 ProbeForWriteHandle(ProcessHandle
);
952 ProbeForRead(ClientId
,
956 SafeClientId
= *ClientId
;
957 ClientId
= &SafeClientId
;
960 /* just probe the object attributes structure, don't capture it
961 completely. This is done later if necessary */
962 ProbeForRead(ObjectAttributes
,
963 sizeof(OBJECT_ATTRIBUTES
),
965 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
966 Attributes
= ObjectAttributes
->Attributes
;
970 Status
= _SEH_GetExceptionCode();
974 if(!NT_SUCCESS(Status
)) return Status
;
978 HasObjectName
= (ObjectAttributes
->ObjectName
!= NULL
);
979 Attributes
= ObjectAttributes
->Attributes
;
982 if (HasObjectName
&& ClientId
!= NULL
)
984 /* can't pass both, n object name and a client id */
985 return STATUS_INVALID_PARAMETER_MIX
;
988 /* Open by name if one was given */
989 DPRINT("Checking type\n");
993 DPRINT("Opening by name\n");
994 Status
= ObOpenObjectByName(ObjectAttributes
,
1002 if (!NT_SUCCESS(Status
))
1004 DPRINT1("Could not open object by name\n");
1007 else if (ClientId
!= NULL
)
1009 /* Open by Thread ID */
1010 if (ClientId
->UniqueThread
)
1012 /* Get the Process */
1013 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
1014 Status
= PsLookupProcessThreadByCid(ClientId
,
1020 /* Get the Process */
1021 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
);
1022 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
1026 if(!NT_SUCCESS(Status
))
1028 DPRINT1("Failure to find process\n");
1032 /* Open the Process Object */
1033 Status
= ObOpenObjectByPointer(Process
,
1040 if(!NT_SUCCESS(Status
))
1042 DPRINT1("Failure to open process\n");
1045 /* Dereference the thread if we used it */
1046 if (Thread
) ObDereferenceObject(Thread
);
1048 /* Dereference the Process */
1049 ObDereferenceObject(Process
);
1053 /* neither an object name nor a client id was passed */
1054 return STATUS_INVALID_PARAMETER_MIX
;
1057 /* Write back the handle */
1058 if(NT_SUCCESS(Status
))
1062 *ProcessHandle
= hProcess
;
1066 Status
= _SEH_GetExceptionCode();