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 *****************************************************************/
33 PsLockProcess(PEPROCESS Process
, BOOLEAN Timeout
)
36 PKTHREAD PrevLockOwner
;
37 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
38 PLARGE_INTEGER Delay
= (Timeout
? &PsLockTimeout
: NULL
);
39 PKTHREAD CallingThread
= KeGetCurrentThread();
43 KeEnterCriticalRegion();
47 PrevLockOwner
= (PKTHREAD
)InterlockedCompareExchangePointer(
48 &Process
->LockOwner
, CallingThread
, NULL
);
49 if(PrevLockOwner
== NULL
|| PrevLockOwner
== CallingThread
)
51 /* we got the lock or already locked it */
52 if(InterlockedIncrementUL(&Process
->LockCount
) == 1)
54 KeClearEvent(&Process
->LockEvent
);
57 return STATUS_SUCCESS
;
63 Status
= KeWaitForSingleObject(&Process
->LockEvent
,
68 if(!NT_SUCCESS(Status
) || Status
== STATUS_TIMEOUT
)
71 if(Status
== STATUS_TIMEOUT
)
73 DPRINT1("PsLockProcess(0x%x) timed out!\n", Process
);
76 KeLeaveCriticalRegion();
82 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
91 PsUnlockProcess(PEPROCESS Process
)
95 ASSERT(Process
->LockOwner
== KeGetCurrentThread());
97 if(InterlockedDecrementUL(&Process
->LockCount
) == 0)
99 InterlockedExchangePointer(&Process
->LockOwner
, NULL
);
100 KeSetEvent(&Process
->LockEvent
, IO_NO_INCREMENT
, FALSE
);
103 KeLeaveCriticalRegion();
108 PsGetNextProcess(PEPROCESS OldProcess
)
110 PEPROCESS NextProcess
;
113 /* Check if we have a previous process */
114 if (OldProcess
== NULL
)
116 /* We don't, start with the Idle Process */
117 Status
= ObReferenceObjectByPointer(PsIdleProcess
,
121 if (!NT_SUCCESS(Status
))
123 DPRINT1("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsIdleProcess\n");
127 return PsIdleProcess
;
130 /* Acquire the Active Process Lock */
131 ExAcquireFastMutex(&PspActiveProcessMutex
);
133 /* Start at the previous process */
134 NextProcess
= OldProcess
;
136 /* Loop until we fail */
139 /* Get the Process Link */
140 PLIST_ENTRY Flink
= (NextProcess
== PsIdleProcess
? PsActiveProcessHead
.Flink
:
141 NextProcess
->ActiveProcessLinks
.Flink
);
143 /* Move to the next Process if we're not back at the beginning */
144 if (Flink
!= &PsActiveProcessHead
)
146 NextProcess
= CONTAINING_RECORD(Flink
, EPROCESS
, ActiveProcessLinks
);
154 /* Reference the Process */
155 Status
= ObReferenceObjectByPointer(NextProcess
,
160 /* Exit the loop if the reference worked, keep going if there's an error */
161 if (NT_SUCCESS(Status
)) break;
164 /* Release the lock */
165 ExReleaseFastMutex(&PspActiveProcessMutex
);
167 /* Reference the Process we had referenced earlier */
168 ObDereferenceObject(OldProcess
);
174 PspCreateProcess(OUT PHANDLE ProcessHandle
,
175 IN ACCESS_MASK DesiredAccess
,
176 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
177 IN HANDLE ParentProcess OPTIONAL
,
178 IN BOOLEAN InheritObjectTable
,
179 IN HANDLE SectionHandle OPTIONAL
,
180 IN HANDLE DebugPort OPTIONAL
,
181 IN HANDLE ExceptionPort OPTIONAL
)
185 PEPROCESS pParentProcess
;
186 PEPORT pDebugPort
= NULL
;
187 PEPORT pExceptionPort
= NULL
;
188 PSECTION_OBJECT SectionObject
= NULL
;
189 NTSTATUS Status
= STATUS_SUCCESS
;
190 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
191 PHYSICAL_ADDRESS DirectoryTableBase
;
193 HANDLE_TABLE_ENTRY CidEntry
;
194 DirectoryTableBase
.QuadPart
= (ULONGLONG
)0;
196 DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes
);
198 /* Reference the Parent if there is one */
199 if(ParentProcess
!= NULL
)
201 Status
= ObReferenceObjectByHandle(ParentProcess
,
202 PROCESS_CREATE_PROCESS
,
205 (PVOID
*)&pParentProcess
,
208 if (!NT_SUCCESS(Status
))
210 DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status
);
214 /* Inherit Parent process's Affinity. */
215 Affinity
= pParentProcess
->Pcb
.Affinity
;
220 pParentProcess
= NULL
;
221 Affinity
= KeActiveProcessors
;
224 /* Add the debug port */
225 if (DebugPort
!= NULL
)
227 Status
= ObReferenceObjectByHandle(DebugPort
,
233 if (!NT_SUCCESS(Status
))
235 DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status
);
236 goto exitdereferenceobjects
;
240 /* Add the exception port */
241 if (ExceptionPort
!= NULL
)
243 Status
= ObReferenceObjectByHandle(ExceptionPort
,
247 (PVOID
*)&pExceptionPort
,
250 if (!NT_SUCCESS(Status
))
252 DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status
);
253 goto exitdereferenceobjects
;
257 /* Add the Section */
258 if (SectionHandle
!= NULL
)
260 Status
= ObReferenceObjectByHandle(SectionHandle
,
264 (PVOID
*)&SectionObject
,
266 if (!NT_SUCCESS(Status
))
268 DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status
);
269 goto exitdereferenceobjects
;
273 /* Create the Object */
274 DPRINT("Creating Process Object\n");
275 Status
= ObCreateObject(PreviousMode
,
285 if (!NT_SUCCESS(Status
))
287 DPRINT1("Failed to create process object, Status: 0x%x\n", Status
);
288 goto exitdereferenceobjects
;
291 /* Clean up the Object */
292 DPRINT("Cleaning Process Object\n");
293 RtlZeroMemory(Process
, sizeof(EPROCESS
));
295 /* Inherit stuff from the Parent since we now have the object created */
298 Process
->InheritedFromUniqueProcessId
= pParentProcess
->UniqueProcessId
;
299 Process
->Session
= pParentProcess
->Session
;
302 /* Set up the Quota Block from the Parent */
303 PspInheritQuota(Process
, pParentProcess
);
305 /* FIXME: Set up Dos Device Map from the Parent
306 ObInheritDeviceMap(Parent, Process) */
308 /* Set the Process' LPC Ports */
309 Process
->DebugPort
= pDebugPort
;
310 Process
->ExceptionPort
= pExceptionPort
;
312 /* Setup the Lock Event */
313 DPRINT("Initialzing Process Lock\n");
314 KeInitializeEvent(&Process
->LockEvent
, SynchronizationEvent
, FALSE
);
316 /* Setup the Thread List Head */
317 DPRINT("Initialzing Process ThreadListHead\n");
318 InitializeListHead(&Process
->ThreadListHead
);
320 /* Create or Clone the Handle Table */
321 DPRINT("Initialzing Process Handle Table\n");
322 ObCreateHandleTable(pParentProcess
, InheritObjectTable
, Process
);
323 DPRINT("Handle Table: %x\n", Process
->ObjectTable
);
325 /* Set Process's Directory Base */
326 DPRINT("Initialzing Process Directory Base\n");
327 MmCopyMmInfo(pParentProcess
? pParentProcess
: PsInitialSystemProcess
,
329 &DirectoryTableBase
);
331 /* Now initialize the Kernel Process */
332 DPRINT("Initialzing Kernel Process\n");
333 KeInitializeProcess(&Process
->Pcb
,
338 /* Duplicate Parent Token */
339 DPRINT("Initialzing Process Token\n");
340 Status
= PspInitializeProcessSecurity(Process
, pParentProcess
);
341 if (!NT_SUCCESS(Status
))
343 DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status
);
344 ObDereferenceObject(Process
);
345 goto exitdereferenceobjects
;
348 /* Create the Process' Address Space */
349 DPRINT("Initialzing Process Address Space\n");
350 Status
= MmCreateProcessAddressSpace(Process
, SectionObject
);
351 if (!NT_SUCCESS(Status
))
353 DPRINT1("Failed to create Address Space\n");
354 ObDereferenceObject(Process
);
355 goto exitdereferenceobjects
;
360 /* Map the System Dll */
361 DPRINT("Mapping System DLL\n");
362 PspMapSystemDll(Process
, NULL
);
365 /* Create a handle for the Process */
366 DPRINT("Initialzing Process CID Handle\n");
367 CidEntry
.u1
.Object
= Process
;
368 CidEntry
.u2
.GrantedAccess
= 0;
369 Process
->UniqueProcessId
= (ExCreateHandle(PspCidTable
, &CidEntry
));
370 DPRINT("Created CID: %d\n", Process
->UniqueProcessId
);
371 if(!Process
->UniqueProcessId
)
373 DPRINT1("Failed to create CID handle\n");
374 ObDereferenceObject(Process
);
375 goto exitdereferenceobjects
;
378 /* FIXME: Insert into Job Object */
380 /* Create PEB only for User-Mode Processes */
383 DPRINT("Creating PEB\n");
384 Status
= MmCreatePeb(Process
);
385 if (!NT_SUCCESS(Status
))
387 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
388 ObDereferenceObject(Process
);
389 goto exitdereferenceobjects
;
392 /* Let's take advantage of this time to kill the reference too */
393 ObDereferenceObject(pParentProcess
);
394 pParentProcess
= NULL
;
397 /* W00T! The process can now be activated */
398 DPRINT("Inserting into Active Process List\n");
399 ExAcquireFastMutex(&PspActiveProcessMutex
);
400 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
401 ExReleaseFastMutex(&PspActiveProcessMutex
);
403 /* FIXME: SeCreateAccessStateEx */
405 /* Insert the Process into the Object Directory */
406 DPRINT("Inserting Process Object\n");
407 Status
= ObInsertObject(Process
,
413 if (!NT_SUCCESS(Status
))
415 DPRINT1("Could not get a handle to the Process Object\n");
416 ObDereferenceObject(Process
);
417 goto exitdereferenceobjects
;
420 /* Set the Creation Time */
421 KeQuerySystemTime(&Process
->CreateTime
);
423 DPRINT("Done. Returning handle: %x\n", hProcess
);
426 *ProcessHandle
= hProcess
;
430 Status
= _SEH_GetExceptionCode();
433 /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
436 ObDereferenceObject(Process
);
439 exitdereferenceobjects
:
440 if(SectionObject
!= NULL
) ObDereferenceObject(SectionObject
);
441 if(pExceptionPort
!= NULL
) ObDereferenceObject(pExceptionPort
);
442 if(pDebugPort
!= NULL
) ObDereferenceObject(pDebugPort
);
443 if(pParentProcess
!= NULL
) ObDereferenceObject(pParentProcess
);
447 /* PUBLIC FUNCTIONS *****************************************************************/
454 PsCreateSystemProcess(PHANDLE ProcessHandle
,
455 ACCESS_MASK DesiredAccess
,
456 POBJECT_ATTRIBUTES ObjectAttributes
)
458 return PspCreateProcess(ProcessHandle
,
461 NULL
, /* no parent process */
473 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
474 OUT PEPROCESS
*Process
)
476 PHANDLE_TABLE_ENTRY CidEntry
;
477 PEPROCESS FoundProcess
;
478 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
481 /* Get the CID Handle Entry */
482 if (!(CidEntry
= ExMapHandleToPointer(PspCidTable
,
483 HANDLE_TO_EX_HANDLE(ProcessId
))))
485 /* Get the Process */
486 FoundProcess
= CidEntry
->u1
.Object
;
488 /* Make sure it's really a process */
489 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
491 /* Reference and return it */
492 ObReferenceObject(FoundProcess
);
493 *Process
= FoundProcess
;
494 Status
= STATUS_SUCCESS
;
497 /* Unlock the Entry */
498 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
501 /* Return to caller */
510 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
511 OUT PEPROCESS
*Process OPTIONAL
,
512 OUT PETHREAD
*Thread
)
514 PHANDLE_TABLE_ENTRY CidEntry
;
515 PETHREAD FoundThread
;
516 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
519 /* Get the CID Handle Entry */
520 if (!(CidEntry
= ExMapHandleToPointer(PspCidTable
,
521 HANDLE_TO_EX_HANDLE(Cid
->UniqueThread
))))
523 /* Get the Process */
524 FoundThread
= CidEntry
->u1
.Object
;
526 /* Make sure it's really a thread and this process' */
527 if ((FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
) &&
528 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
530 /* Reference and return it */
531 ObReferenceObject(FoundThread
);
532 *Thread
= FoundThread
;
533 Status
= STATUS_SUCCESS
;
535 /* Check if we should return the Process too */
538 /* Return it and reference it */
539 *Process
= FoundThread
->ThreadsProcess
;
540 ObReferenceObject(*Process
);
544 /* Unlock the Entry */
545 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
548 /* Return to caller */
553 * FUNCTION: Returns a pointer to the current process
558 IoGetCurrentProcess(VOID
)
560 if (PsGetCurrentThread() == NULL
||
561 PsGetCurrentThread()->Tcb
.ApcState
.Process
== NULL
)
563 return(PsInitialSystemProcess
);
567 return(PEPROCESS
)(PsGetCurrentThread()->Tcb
.ApcState
.Process
);
574 LARGE_INTEGER STDCALL
575 PsGetProcessExitTime(VOID
)
578 Li
.QuadPart
= PsGetCurrentProcess()->ExitTime
.QuadPart
;
587 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
589 return Process
->CreateTime
.QuadPart
;
597 PsGetProcessDebugPort(PEPROCESS Process
)
599 return Process
->DebugPort
;
607 PsGetProcessExitProcessCalled(PEPROCESS Process
)
609 return Process
->ProcessExiting
;
617 PsGetProcessExitStatus(PEPROCESS Process
)
619 return Process
->ExitStatus
;
627 PsGetProcessId(PEPROCESS Process
)
629 return (HANDLE
)Process
->UniqueProcessId
;
637 PsGetProcessImageFileName(PEPROCESS Process
)
639 return (LPSTR
)Process
->ImageFileName
;
647 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
649 return Process
->InheritedFromUniqueProcessId
;
657 PsGetProcessJob(PEPROCESS Process
)
667 PsGetProcessPeb(PEPROCESS Process
)
677 PsGetProcessPriorityClass(PEPROCESS Process
)
679 return Process
->PriorityClass
;
686 PsGetCurrentProcessId(VOID
)
688 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
696 PsGetCurrentProcessSessionId(VOID
)
698 return PsGetCurrentProcess()->Session
;
706 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
708 return Process
->SectionBaseAddress
;
716 PsGetProcessSecurityPort(PEPROCESS Process
)
718 return Process
->SecurityPort
;
726 PsGetProcessSessionId(PEPROCESS Process
)
728 return (HANDLE
)Process
->Session
;
733 PsGetWin32Thread(VOID
)
735 return(PsGetCurrentThread()->Tcb
.Win32Thread
);
740 PsGetWin32Process(VOID
)
742 return (struct _W32PROCESS
*)PsGetCurrentProcess()->Win32Process
;
750 PsGetProcessWin32Process(PEPROCESS Process
)
752 return Process
->Win32Process
;
760 PsGetProcessWin32WindowStation(PEPROCESS Process
)
762 return Process
->Win32WindowStation
;
770 PsIsProcessBeingDebugged(PEPROCESS Process
)
772 return FALSE
; //Process->IsProcessBeingDebugged;
780 PsSetProcessPriorityClass(PEPROCESS Process
,
783 Process
->PriorityClass
= PriorityClass
;
791 PsSetProcessSecurityPort(PEPROCESS Process
,
794 Process
->SecurityPort
= SecurityPort
;
802 PsSetProcessWin32Process(PEPROCESS Process
,
805 Process
->Win32Process
= Win32Process
;
813 PsSetProcessWindowStation(PEPROCESS Process
,
816 Process
->Win32WindowStation
= WindowStation
;
824 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
828 return STATUS_NOT_IMPLEMENTED
;
832 * FUNCTION: Creates a process.
834 * ProcessHandle (OUT) = Caller supplied storage for the resulting
836 * DesiredAccess = Specifies the allowed or desired access to the
837 * process can be a combination of
838 * STANDARD_RIGHTS_REQUIRED| ..
839 * ObjectAttribute = Initialized attributes for the object, contains
840 * the rootdirectory and the filename
841 * ParentProcess = Handle to the parent process.
842 * InheritObjectTable = Specifies to inherit the objects of the parent
844 * SectionHandle = Handle to a section object to back the image file
845 * DebugPort = Handle to a DebugPort if NULL the system default debug
847 * ExceptionPort = Handle to a exception port.
849 * This function maps to the win32 CreateProcess.
856 NtCreateProcess(OUT PHANDLE ProcessHandle
,
857 IN ACCESS_MASK DesiredAccess
,
858 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
859 IN HANDLE ParentProcess
,
860 IN BOOLEAN InheritObjectTable
,
861 IN HANDLE SectionHandle OPTIONAL
,
862 IN HANDLE DebugPort OPTIONAL
,
863 IN HANDLE ExceptionPort OPTIONAL
)
865 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
866 NTSTATUS Status
= STATUS_SUCCESS
;
870 /* Check parameters */
871 if(PreviousMode
!= KernelMode
)
875 ProbeForWrite(ProcessHandle
,
881 Status
= _SEH_GetExceptionCode();
885 if(!NT_SUCCESS(Status
)) return Status
;
888 /* Make sure there's a parent process */
889 if(ParentProcess
== NULL
)
891 /* Can't create System Processes like this */
892 Status
= STATUS_INVALID_PARAMETER
;
896 /* Create a user Process */
897 Status
= PspCreateProcess(ProcessHandle
,
916 NtOpenProcess(OUT PHANDLE ProcessHandle
,
917 IN ACCESS_MASK DesiredAccess
,
918 IN POBJECT_ATTRIBUTES ObjectAttributes
,
919 IN PCLIENT_ID ClientId
)
921 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
922 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
924 PETHREAD Thread
= NULL
;
926 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
927 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
928 ProcessHandle
, DesiredAccess
, ObjectAttributes
, ClientId
,
929 ClientId
->UniqueProcess
, ClientId
->UniqueThread
);
933 /* Open by name if one was given */
934 DPRINT("Checking type\n");
935 if (ObjectAttributes
->ObjectName
)
938 DPRINT("Opening by name\n");
939 Status
= ObOpenObjectByName(ObjectAttributes
,
947 if (Status
!= STATUS_SUCCESS
)
949 DPRINT1("Could not open object by name\n");
953 DPRINT("Found: %x\n", ProcessHandle
);
958 /* Open by Thread ID */
959 if (ClientId
->UniqueThread
)
961 /* Get the Process */
962 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
);
963 Status
= PsLookupProcessThreadByCid(ClientId
,
966 DPRINT("Found: %x\n", Process
);
970 /* Get the Process */
971 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
);
972 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
,
974 DPRINT("Found: %x\n", Process
);
977 if(!NT_SUCCESS(Status
))
979 DPRINT1("Failure to find process\n");
983 /* Open the Process Object */
984 Status
= ObOpenObjectByPointer(Process
,
985 ObjectAttributes
->Attributes
,
991 if(!NT_SUCCESS(Status
))
993 DPRINT1("Failure to open process\n");
996 /* Dereference the thread if we used it */
997 if (Thread
) ObDereferenceObject(Thread
);
999 /* Dereference the Process */
1000 ObDereferenceObject(Process
);