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
)
187 PEPROCESS pParentProcess
;
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;
198 DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes
);
200 /* Reference the Parent if there is one */
201 if(ParentProcess
!= NULL
)
203 Status
= ObReferenceObjectByHandle(ParentProcess
,
204 PROCESS_CREATE_PROCESS
,
207 (PVOID
*)&pParentProcess
,
210 if (!NT_SUCCESS(Status
))
212 DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status
);
216 /* Inherit Parent process's Affinity. */
217 Affinity
= pParentProcess
->Pcb
.Affinity
;
222 pParentProcess
= NULL
;
223 Affinity
= KeActiveProcessors
;
226 /* Add the debug port */
227 if (DebugPort
!= NULL
)
229 Status
= ObReferenceObjectByHandle(DebugPort
,
235 if (!NT_SUCCESS(Status
))
237 DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status
);
238 goto exitdereferenceobjects
;
242 /* Add the exception port */
243 if (ExceptionPort
!= NULL
)
245 Status
= ObReferenceObjectByHandle(ExceptionPort
,
249 (PVOID
*)&pExceptionPort
,
252 if (!NT_SUCCESS(Status
))
254 DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status
);
255 goto exitdereferenceobjects
;
259 /* Add the Section */
260 if (SectionHandle
!= NULL
)
262 Status
= ObReferenceObjectByHandle(SectionHandle
,
266 (PVOID
*)&SectionObject
,
268 if (!NT_SUCCESS(Status
))
270 DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status
);
271 goto exitdereferenceobjects
;
275 /* Create the Object */
276 DPRINT("Creating Process Object\n");
277 Status
= ObCreateObject(PreviousMode
,
287 if (!NT_SUCCESS(Status
))
289 DPRINT1("Failed to create process object, Status: 0x%x\n", Status
);
290 goto exitdereferenceobjects
;
293 /* Clean up the Object */
294 DPRINT("Cleaning Process Object\n");
295 RtlZeroMemory(Process
, sizeof(EPROCESS
));
297 /* Inherit stuff from the Parent since we now have the object created */
300 Process
->InheritedFromUniqueProcessId
= pParentProcess
->UniqueProcessId
;
301 Process
->Session
= pParentProcess
->Session
;
304 /* Set up the Quota Block from the Parent */
305 PspInheritQuota(Process
, pParentProcess
);
307 /* FIXME: Set up Dos Device Map from the Parent
308 ObInheritDeviceMap(Parent, Process) */
310 /* Set the Process' LPC Ports */
311 Process
->DebugPort
= pDebugPort
;
312 Process
->ExceptionPort
= pExceptionPort
;
314 /* Setup the Lock Event */
315 DPRINT("Initialzing Process Lock\n");
316 KeInitializeEvent(&Process
->LockEvent
, SynchronizationEvent
, FALSE
);
318 /* Setup the Thread List Head */
319 DPRINT("Initialzing Process ThreadListHead\n");
320 InitializeListHead(&Process
->ThreadListHead
);
322 /* Create or Clone the Handle Table */
323 DPRINT("Initialzing Process Handle Table\n");
324 ObCreateHandleTable(pParentProcess
, InheritObjectTable
, Process
);
325 DPRINT("Handle Table: %x\n", Process
->ObjectTable
);
327 /* Set Process's Directory Base */
328 DPRINT("Initialzing Process Directory Base\n");
329 MmCopyMmInfo(pParentProcess
? pParentProcess
: PsInitialSystemProcess
,
331 &DirectoryTableBase
);
333 /* Now initialize the Kernel Process */
334 DPRINT("Initialzing Kernel Process\n");
335 KeInitializeProcess(&Process
->Pcb
,
336 PROCESS_PRIORITY_NORMAL
,
340 /* Duplicate Parent Token */
341 DPRINT("Initialzing Process Token\n");
342 Status
= PspInitializeProcessSecurity(Process
, pParentProcess
);
343 if (!NT_SUCCESS(Status
))
345 DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status
);
346 ObDereferenceObject(Process
);
347 goto exitdereferenceobjects
;
350 /* Create the Process' Address Space */
351 DPRINT("Initialzing Process Address Space\n");
352 Status
= MmCreateProcessAddressSpace(Process
, SectionObject
);
353 if (!NT_SUCCESS(Status
))
355 DPRINT1("Failed to create Address Space\n");
356 ObDereferenceObject(Process
);
357 goto exitdereferenceobjects
;
362 /* Map the System Dll */
363 DPRINT("Mapping System DLL\n");
364 PspMapSystemDll(Process
, NULL
);
367 /* Create a handle for the Process */
368 DPRINT("Initialzing Process CID Handle\n");
369 CidEntry
.u1
.Object
= Process
;
370 CidEntry
.u2
.GrantedAccess
= 0;
371 Process
->UniqueProcessId
= ExCreateHandle(PspCidTable
, &CidEntry
);
372 DPRINT("Created CID: %d\n", Process
->UniqueProcessId
);
373 if(!Process
->UniqueProcessId
)
375 DPRINT1("Failed to create CID handle\n");
376 ObDereferenceObject(Process
);
377 goto exitdereferenceobjects
;
380 /* FIXME: Insert into Job Object */
382 /* Create PEB only for User-Mode Processes */
385 DPRINT("Creating PEB\n");
386 Status
= MmCreatePeb(Process
);
387 if (!NT_SUCCESS(Status
))
389 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
390 ObDereferenceObject(Process
);
391 goto exitdereferenceobjects
;
394 /* Let's take advantage of this time to kill the reference too */
395 ObDereferenceObject(pParentProcess
);
396 pParentProcess
= NULL
;
399 /* W00T! The process can now be activated */
400 DPRINT("Inserting into Active Process List\n");
401 ExAcquireFastMutex(&PspActiveProcessMutex
);
402 InsertTailList(&PsActiveProcessHead
, &Process
->ActiveProcessLinks
);
403 ExReleaseFastMutex(&PspActiveProcessMutex
);
405 /* FIXME: SeCreateAccessStateEx */
407 /* Insert the Process into the Object Directory */
408 DPRINT("Inserting Process Object\n");
409 Status
= ObInsertObject(Process
,
415 if (!NT_SUCCESS(Status
))
417 DPRINT1("Could not get a handle to the Process Object\n");
418 ObDereferenceObject(Process
);
419 goto exitdereferenceobjects
;
422 /* Set the Creation Time */
423 KeQuerySystemTime(&Process
->CreateTime
);
425 DPRINT("Done. Returning handle: %x\n", hProcess
);
428 *ProcessHandle
= hProcess
;
432 Status
= _SEH_GetExceptionCode();
435 /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
438 ObDereferenceObject(Process
);
441 exitdereferenceobjects
:
442 if(SectionObject
!= NULL
) ObDereferenceObject(SectionObject
);
443 if(pExceptionPort
!= NULL
) ObDereferenceObject(pExceptionPort
);
444 if(pDebugPort
!= NULL
) ObDereferenceObject(pDebugPort
);
445 if(pParentProcess
!= NULL
) ObDereferenceObject(pParentProcess
);
449 /* PUBLIC FUNCTIONS *****************************************************************/
456 PsCreateSystemProcess(PHANDLE ProcessHandle
,
457 ACCESS_MASK DesiredAccess
,
458 POBJECT_ATTRIBUTES ObjectAttributes
)
460 return PspCreateProcess(ProcessHandle
,
463 NULL
, /* no parent process */
475 PsLookupProcessByProcessId(IN HANDLE ProcessId
,
476 OUT PEPROCESS
*Process
)
478 PHANDLE_TABLE_ENTRY CidEntry
;
479 PEPROCESS FoundProcess
;
480 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
483 KeEnterCriticalRegion();
485 /* Get the CID Handle Entry */
486 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
489 /* Get the Process */
490 FoundProcess
= CidEntry
->u1
.Object
;
492 /* Make sure it's really a process */
493 if (FoundProcess
->Pcb
.Header
.Type
== ProcessObject
)
495 /* Reference and return it */
496 ObReferenceObject(FoundProcess
);
497 *Process
= FoundProcess
;
498 Status
= STATUS_SUCCESS
;
501 /* Unlock the Entry */
502 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
505 KeLeaveCriticalRegion();
507 /* Return to caller */
516 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
517 OUT PEPROCESS
*Process OPTIONAL
,
518 OUT PETHREAD
*Thread
)
520 PHANDLE_TABLE_ENTRY CidEntry
;
521 PETHREAD FoundThread
;
522 NTSTATUS Status
= STATUS_INVALID_CID
;
525 KeEnterCriticalRegion();
527 /* Get the CID Handle Entry */
528 if ((CidEntry
= ExMapHandleToPointer(PspCidTable
,
531 /* Get the Process */
532 FoundThread
= CidEntry
->u1
.Object
;
534 /* Make sure it's really a thread and this process' */
535 if ((FoundThread
->Tcb
.DispatcherHeader
.Type
== ThreadObject
) &&
536 (FoundThread
->Cid
.UniqueProcess
== Cid
->UniqueProcess
))
538 /* Reference and return it */
539 ObReferenceObject(FoundThread
);
540 *Thread
= FoundThread
;
541 Status
= STATUS_SUCCESS
;
543 /* Check if we should return the Process too */
546 /* Return it and reference it */
547 *Process
= FoundThread
->ThreadsProcess
;
548 ObReferenceObject(*Process
);
552 /* Unlock the Entry */
553 ExUnlockHandleTableEntry(PspCidTable
, CidEntry
);
556 KeLeaveCriticalRegion();
558 /* Return to caller */
563 * FUNCTION: Returns a pointer to the current process
568 IoGetCurrentProcess(VOID
)
570 if (PsGetCurrentThread() == NULL
||
571 PsGetCurrentThread()->Tcb
.ApcState
.Process
== NULL
)
573 return(PsInitialSystemProcess
);
577 return(PEPROCESS
)(PsGetCurrentThread()->Tcb
.ApcState
.Process
);
584 LARGE_INTEGER STDCALL
585 PsGetProcessExitTime(VOID
)
588 Li
.QuadPart
= PsGetCurrentProcess()->ExitTime
.QuadPart
;
597 PsGetProcessCreateTimeQuadPart(PEPROCESS Process
)
599 return Process
->CreateTime
.QuadPart
;
607 PsGetProcessDebugPort(PEPROCESS Process
)
609 return Process
->DebugPort
;
617 PsGetProcessExitProcessCalled(PEPROCESS Process
)
619 return Process
->ProcessExiting
;
627 PsGetProcessExitStatus(PEPROCESS Process
)
629 return Process
->ExitStatus
;
637 PsGetProcessId(PEPROCESS Process
)
639 return (HANDLE
)Process
->UniqueProcessId
;
647 PsGetProcessImageFileName(PEPROCESS Process
)
649 return (LPSTR
)Process
->ImageFileName
;
657 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process
)
659 return Process
->InheritedFromUniqueProcessId
;
667 PsGetProcessJob(PEPROCESS Process
)
677 PsGetProcessPeb(PEPROCESS Process
)
687 PsGetProcessPriorityClass(PEPROCESS Process
)
689 return Process
->PriorityClass
;
696 PsGetCurrentProcessId(VOID
)
698 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
706 PsGetCurrentProcessSessionId(VOID
)
708 return PsGetCurrentProcess()->Session
;
716 PsGetProcessSectionBaseAddress(PEPROCESS Process
)
718 return Process
->SectionBaseAddress
;
726 PsGetProcessSecurityPort(PEPROCESS Process
)
728 return Process
->SecurityPort
;
736 PsGetProcessSessionId(PEPROCESS Process
)
738 return (HANDLE
)Process
->Session
;
743 PsGetWin32Thread(VOID
)
745 return(PsGetCurrentThread()->Tcb
.Win32Thread
);
750 PsGetWin32Process(VOID
)
752 return (struct _W32PROCESS
*)PsGetCurrentProcess()->Win32Process
;
760 PsGetProcessWin32Process(PEPROCESS Process
)
762 return Process
->Win32Process
;
770 PsGetProcessWin32WindowStation(PEPROCESS Process
)
772 return Process
->Win32WindowStation
;
780 PsIsProcessBeingDebugged(PEPROCESS Process
)
782 return FALSE
; //Process->IsProcessBeingDebugged;
790 PsSetProcessPriorityClass(PEPROCESS Process
,
793 Process
->PriorityClass
= PriorityClass
;
801 PsSetProcessSecurityPort(PEPROCESS Process
,
804 Process
->SecurityPort
= SecurityPort
;
812 PsSetProcessWin32Process(PEPROCESS Process
,
815 Process
->Win32Process
= Win32Process
;
823 PsSetProcessWindowStation(PEPROCESS Process
,
826 Process
->Win32WindowStation
= WindowStation
;
834 PsSetProcessPriorityByClass(IN PEPROCESS Process
,
838 return STATUS_NOT_IMPLEMENTED
;
842 * FUNCTION: Creates a process.
844 * ProcessHandle (OUT) = Caller supplied storage for the resulting
846 * DesiredAccess = Specifies the allowed or desired access to the
847 * process can be a combination of
848 * STANDARD_RIGHTS_REQUIRED| ..
849 * ObjectAttribute = Initialized attributes for the object, contains
850 * the rootdirectory and the filename
851 * ParentProcess = Handle to the parent process.
852 * InheritObjectTable = Specifies to inherit the objects of the parent
854 * SectionHandle = Handle to a section object to back the image file
855 * DebugPort = Handle to a DebugPort if NULL the system default debug
857 * ExceptionPort = Handle to a exception port.
859 * This function maps to the win32 CreateProcess.
866 NtCreateProcess(OUT PHANDLE ProcessHandle
,
867 IN ACCESS_MASK DesiredAccess
,
868 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
869 IN HANDLE ParentProcess
,
870 IN BOOLEAN InheritObjectTable
,
871 IN HANDLE SectionHandle OPTIONAL
,
872 IN HANDLE DebugPort OPTIONAL
,
873 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, do NOT pass the pointer to the handle supplied
906 by the caller directly!!! */
907 Status
= PspCreateProcess(&hProcess
,
915 if (NT_SUCCESS(Status
))
919 *ProcessHandle
= hProcess
;
923 Status
= _SEH_GetExceptionCode();
938 NtOpenProcess(OUT PHANDLE ProcessHandle
,
939 IN ACCESS_MASK DesiredAccess
,
940 IN POBJECT_ATTRIBUTES ObjectAttributes
,
941 IN PCLIENT_ID ClientId
)
943 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
944 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
946 PETHREAD Thread
= NULL
;
948 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
949 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
950 ProcessHandle
, DesiredAccess
, ObjectAttributes
, ClientId
,
951 ClientId
->UniqueProcess
, ClientId
->UniqueThread
);
955 /* Open by name if one was given */
956 DPRINT("Checking type\n");
957 if (ObjectAttributes
->ObjectName
) /* FIXME - neither probed nor protected! */
960 DPRINT("Opening by name\n");
961 Status
= ObOpenObjectByName(ObjectAttributes
,
969 if (Status
!= STATUS_SUCCESS
)
971 DPRINT1("Could not open object by name\n");
975 DPRINT("Found: %x\n", ProcessHandle
);
980 /* Open by Thread ID */
981 if (ClientId
->UniqueThread
) /* FIXME - neither probed nor protected! */
983 /* Get the Process */
984 DPRINT("Opening by Thread ID: %x\n", ClientId
->UniqueThread
); /* FIXME - neither probed nor protected! */
985 Status
= PsLookupProcessThreadByCid(ClientId
, /* FIXME - neither probed nor protected! */
988 DPRINT("Found: %x\n", Process
);
992 /* Get the Process */
993 DPRINT("Opening by Process ID: %x\n", ClientId
->UniqueProcess
); /* FIXME - neither probed nor protected! */
994 Status
= PsLookupProcessByProcessId(ClientId
->UniqueProcess
, /* FIXME - neither probed nor protected! */
996 DPRINT("Found: %x\n", Process
);
999 if(!NT_SUCCESS(Status
))
1001 DPRINT1("Failure to find process\n");
1005 /* Open the Process Object */
1006 Status
= ObOpenObjectByPointer(Process
,
1007 ObjectAttributes
->Attributes
, /* FIXME - neither probed nor protected! */
1012 ProcessHandle
); /* FIXME - neither probed nor protected! */
1013 if(!NT_SUCCESS(Status
))
1015 DPRINT1("Failure to open process\n");
1018 /* Dereference the thread if we used it */
1019 if (Thread
) ObDereferenceObject(Thread
);
1021 /* Dereference the Process */
1022 ObDereferenceObject(Process
);