1 /* $Id: process.c,v 1.51 2000/07/07 00:49:02 phreak Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/process.c
6 * PURPOSE: Process managment
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES ******************************************************************/
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <internal/mm.h>
18 #include <internal/ke.h>
19 #include <internal/ps.h>
21 #include <internal/string.h>
22 #include <internal/id.h>
24 #include <internal/ldr.h>
25 #include <internal/port.h>
27 #include <internal/dbg.h>
30 #include <internal/debug.h>
32 /* GLOBALS ******************************************************************/
34 PEPROCESS EXPORTED PsInitialSystemProcess
= NULL
;
35 HANDLE SystemProcessHandle
= NULL
;
37 POBJECT_TYPE EXPORTED PsProcessType
= NULL
;
39 static LIST_ENTRY PsProcessListHead
;
40 static KSPIN_LOCK PsProcessListLock
;
41 static ULONG PiNextProcessUniqueId
= 0;
43 /* FUNCTIONS *****************************************************************/
46 PEPROCESS
PsGetNextProcess(PEPROCESS OldProcess
)
49 PEPROCESS NextProcess
;
52 if (OldProcess
== NULL
)
54 return(PsInitialSystemProcess
);
57 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
58 if (OldProcess
->ProcessListEntry
.Flink
== &PsProcessListHead
)
60 NextProcess
= CONTAINING_RECORD(PsProcessListHead
.Flink
,
66 NextProcess
= CONTAINING_RECORD(OldProcess
->ProcessListEntry
.Flink
,
70 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
71 Status
= ObReferenceObjectByPointer(NextProcess
,
75 if (!NT_SUCCESS(Status
))
77 DbgPrint("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
80 ObDereferenceObject(OldProcess
);
85 NTSTATUS STDCALL
NtOpenProcessToken(IN HANDLE ProcessHandle
,
86 IN ACCESS_MASK DesiredAccess
,
87 OUT PHANDLE TokenHandle
)
92 Status
= PsOpenTokenOfProcess(ProcessHandle
,
94 if (!NT_SUCCESS(Status
))
98 Status
= ObCreateHandle(PsGetCurrentProcess(),
103 ObDereferenceObject(Token
);
107 PACCESS_TOKEN STDCALL
PsReferencePrimaryToken(PEPROCESS Process
)
109 ObReferenceObjectByPointer(Process
->Token
,
113 return(Process
->Token
);
116 NTSTATUS
PsOpenTokenOfProcess(HANDLE ProcessHandle
,
117 PACCESS_TOKEN
* Token
)
122 Status
= ObReferenceObjectByHandle(ProcessHandle
,
123 PROCESS_QUERY_INFORMATION
,
128 if (!NT_SUCCESS(Status
))
132 *Token
= PsReferencePrimaryToken(Process
);
133 ObDereferenceObject(Process
);
134 return(STATUS_SUCCESS
);
137 VOID
PiKillMostProcesses(VOID
)
140 PLIST_ENTRY current_entry
;
143 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
145 current_entry
= PsProcessListHead
.Flink
;
146 while (current_entry
!= &PsProcessListHead
)
148 current
= CONTAINING_RECORD(current_entry
, EPROCESS
,
150 current_entry
= current_entry
->Flink
;
152 if (current
->UniqueProcessId
!= PsInitialSystemProcess
->UniqueProcessId
&&
153 current
->UniqueProcessId
!= (ULONG
)PsGetCurrentProcessId())
155 PiTerminateProcessThreads(current
, STATUS_SUCCESS
);
159 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
162 VOID
PsInitProcessManagment(VOID
)
169 * Register the process object type
172 PsProcessType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
174 PsProcessType
->TotalObjects
= 0;
175 PsProcessType
->TotalHandles
= 0;
176 PsProcessType
->MaxObjects
= ULONG_MAX
;
177 PsProcessType
->MaxHandles
= ULONG_MAX
;
178 PsProcessType
->PagedPoolCharge
= 0;
179 PsProcessType
->NonpagedPoolCharge
= sizeof(EPROCESS
);
180 PsProcessType
->Dump
= NULL
;
181 PsProcessType
->Open
= NULL
;
182 PsProcessType
->Close
= NULL
;
183 PsProcessType
->Delete
= PiDeleteProcess
;
184 PsProcessType
->Parse
= NULL
;
185 PsProcessType
->Security
= NULL
;
186 PsProcessType
->QueryName
= NULL
;
187 PsProcessType
->OkayToClose
= NULL
;
188 PsProcessType
->Create
= NULL
;
190 RtlInitUnicodeString(&PsProcessType
->TypeName
, L
"Process");
192 InitializeListHead(&PsProcessListHead
);
193 KeInitializeSpinLock(&PsProcessListLock
);
196 * Initialize the system process
198 PsInitialSystemProcess
= ObCreateObject(NULL
,
202 PsInitialSystemProcess
->Pcb
.BasePriority
= PROCESS_PRIO_NORMAL
;
203 KeInitializeDispatcherHeader(&PsInitialSystemProcess
->Pcb
.DispatcherHeader
,
207 KProcess
= &PsInitialSystemProcess
->Pcb
;
209 MmInitializeAddressSpace(PsInitialSystemProcess
,
210 &PsInitialSystemProcess
->AddressSpace
);
211 ObCreateHandleTable(NULL
,FALSE
,PsInitialSystemProcess
);
212 KProcess
->PageTableDirectory
= get_page_directory();
213 PsInitialSystemProcess
->UniqueProcessId
=
214 InterlockedIncrement(&PiNextProcessUniqueId
);
216 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
217 InsertHeadList(&PsProcessListHead
,
218 &PsInitialSystemProcess
->ProcessListEntry
);
219 InitializeListHead(&PsInitialSystemProcess
->ThreadListHead
);
220 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
222 strcpy(PsInitialSystemProcess
->ImageFileName
, "SYSTEM");
224 ObCreateHandle(PsInitialSystemProcess
,
225 PsInitialSystemProcess
,
228 &SystemProcessHandle
);
231 VOID
PiDeleteProcess(PVOID ObjectBody
)
235 DPRINT1("PiDeleteProcess(ObjectBody %x)\n",ObjectBody
);
237 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
238 RemoveEntryList(&((PEPROCESS
)ObjectBody
)->ProcessListEntry
);
239 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
240 (VOID
)MmReleaseMmInfo((PEPROCESS
)ObjectBody
);
241 ObDeleteHandleTable((PEPROCESS
)ObjectBody
);
245 static NTSTATUS
PsCreatePeb(HANDLE ProcessHandle
,
255 memset(&Peb
, 0, sizeof(Peb
));
256 Peb
.ImageBaseAddress
= ImageBase
;
258 PebBase
= (PVOID
)PEB_BASE
;
260 Status
= NtAllocateVirtualMemory(ProcessHandle
,
266 if (!NT_SUCCESS(Status
))
271 ZwWriteVirtualMemory(ProcessHandle
,
277 DPRINT("PsCreatePeb: Peb created at %x\n", PebBase
);
281 return(STATUS_SUCCESS
);
285 PKPROCESS
KeGetCurrentProcess(VOID
)
287 * FUNCTION: Returns a pointer to the current process
290 return(&(PsGetCurrentProcess()->Pcb
));
293 HANDLE STDCALL
PsGetCurrentProcessId(VOID
)
295 return((HANDLE
)PsGetCurrentProcess()->UniqueProcessId
);
299 * FUNCTION: Returns a pointer to the current process
301 PEPROCESS STDCALL
PsGetCurrentProcess(VOID
)
303 if (PsGetCurrentThread() == NULL
||
304 PsGetCurrentThread()->ThreadsProcess
== NULL
)
306 return(PsInitialSystemProcess
);
310 return(PsGetCurrentThread()->ThreadsProcess
);
314 PEPROCESS STDCALL
IoGetCurrentProcess(VOID
)
316 return(PsGetCurrentProcess());
319 NTSTATUS STDCALL
NtCreateProcess (OUT PHANDLE ProcessHandle
,
320 IN ACCESS_MASK DesiredAccess
,
321 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
322 IN HANDLE ParentProcessHandle
,
323 IN BOOLEAN InheritObjectTable
,
324 IN HANDLE SectionHandle OPTIONAL
,
325 IN HANDLE DebugPortHandle OPTIONAL
,
326 IN HANDLE ExceptionPortHandle OPTIONAL
)
328 * FUNCTION: Creates a process.
330 * ProcessHandle (OUT) = Caller supplied storage for the resulting
332 * DesiredAccess = Specifies the allowed or desired access to the
333 * process can be a combination of
334 * STANDARD_RIGHTS_REQUIRED| ..
335 * ObjectAttribute = Initialized attributes for the object, contains
336 * the rootdirectory and the filename
337 * ParentProcess = Handle to the parent process.
338 * InheritObjectTable = Specifies to inherit the objects of the parent
340 * SectionHandle = Handle to a section object to back the image file
341 * DebugPort = Handle to a DebugPort if NULL the system default debug
343 * ExceptionPort = Handle to a exception port.
345 * This function maps to the win32 CreateProcess.
350 PEPROCESS ParentProcess
;
354 PVOID LdrStartupAddr
;
358 PEPORT ExceptionPort
;
360 DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes
);
362 Status
= ObReferenceObjectByHandle(ParentProcessHandle
,
363 PROCESS_CREATE_PROCESS
,
366 (PVOID
*)&ParentProcess
,
369 if (Status
!= STATUS_SUCCESS
)
371 DPRINT("NtCreateProcess() = %x\n",Status
);
375 Process
= ObCreateObject(ProcessHandle
,
379 KeInitializeDispatcherHeader(&Process
->Pcb
.DispatcherHeader
,
383 KProcess
= &Process
->Pcb
;
385 KProcess
->BasePriority
= PROCESS_PRIO_NORMAL
;
386 MmInitializeAddressSpace(Process
,
387 &Process
->AddressSpace
);
388 Process
->UniqueProcessId
= InterlockedIncrement(&PiNextProcessUniqueId
);
389 Process
->InheritedFromUniqueProcessId
= ParentProcess
->UniqueProcessId
;
390 ObCreateHandleTable(ParentProcess
,
393 MmCopyMmInfo(ParentProcess
, Process
);
395 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
396 InsertHeadList(&PsProcessListHead
, &Process
->ProcessListEntry
);
397 InitializeListHead(&Process
->ThreadListHead
);
398 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
400 Process
->Pcb
.ProcessState
= PROCESS_STATE_ACTIVE
;
405 if (DebugPortHandle
!= NULL
)
407 Status
= ObReferenceObjectByHandle(DebugPortHandle
,
413 if (!NT_SUCCESS(Status
))
415 ObDereferenceObject(Process
);
416 ObDereferenceObject(ParentProcess
);
417 ZwClose(*ProcessHandle
);
418 *ProcessHandle
= NULL
;
421 Process
->DebugPort
= DebugPort
;
425 * Add the exception port
427 if (ExceptionPortHandle
!= NULL
)
429 Status
= ObReferenceObjectByHandle(ExceptionPortHandle
,
433 (PVOID
*)&ExceptionPort
,
435 if (!NT_SUCCESS(Status
))
437 ObDereferenceObject(Process
);
438 ObDereferenceObject(ParentProcess
);
439 ZwClose(*ProcessHandle
);
440 *ProcessHandle
= NULL
;
443 Process
->ExceptionPort
= ExceptionPort
;
447 * Now we have created the process proper
453 Status
= LdrpMapSystemDll(*ProcessHandle
,
455 if (!NT_SUCCESS(Status
))
457 DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status
);
458 ObDereferenceObject(Process
);
459 ObDereferenceObject(ParentProcess
);
464 * Map the process image
466 if (SectionHandle
!= NULL
)
468 DPRINT("Mapping process image\n");
469 Status
= LdrpMapImage(*ProcessHandle
,
472 if (!NT_SUCCESS(Status
))
474 DbgPrint("LdrpMapImage failed (Status %x)\n", Status
);
475 ObDereferenceObject(Process
);
476 ObDereferenceObject(ParentProcess
);
488 DPRINT("Creating PEB\n");
489 Status
= PsCreatePeb(*ProcessHandle
,
492 if (!NT_SUCCESS(Status
))
494 DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status
);
495 ObDereferenceObject(Process
);
496 ObDereferenceObject(ParentProcess
);
497 ZwClose(*ProcessHandle
);
498 *ProcessHandle
= NULL
;
504 * Maybe send a message to the creator process's debugger
506 if (ParentProcess
->DebugPort
!= NULL
)
508 LPC_DBG_MESSAGE Message
;
511 ObCreateHandle(NULL
, // Debugger Process
512 NULL
, // SectionHandle
517 Message
.Header
.MessageSize
= sizeof(LPC_DBG_MESSAGE
);
518 Message
.Header
.DataSize
= sizeof(LPC_DBG_MESSAGE
) -
519 sizeof(LPC_MESSAGE_HEADER
);
520 Message
.Type
= DBG_EVENT_CREATE_PROCESS
;
521 Message
.Data
.CreateProcess
.FileHandle
= FileHandle
;
522 Message
.Data
.CreateProcess
.Base
= ImageBase
;
523 Message
.Data
.CreateProcess
.EntryPoint
= NULL
; //
525 Status
= LpcSendDebugMessagePort(ParentProcess
->DebugPort
,
529 ObDereferenceObject(Process
);
530 ObDereferenceObject(ParentProcess
);
531 return(STATUS_SUCCESS
);
535 NTSTATUS STDCALL
NtOpenProcess (OUT PHANDLE ProcessHandle
,
536 IN ACCESS_MASK DesiredAccess
,
537 IN POBJECT_ATTRIBUTES ObjectAttributes
,
538 IN PCLIENT_ID ClientId
)
540 DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
541 "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
542 ProcessHandle
, DesiredAccess
, ObjectAttributes
, ClientId
,
543 ClientId
->UniqueProcess
, ClientId
->UniqueThread
);
547 * Not sure of the exact semantics
549 if (ObjectAttributes
!= NULL
&& ObjectAttributes
->ObjectName
!= NULL
&&
550 ObjectAttributes
->ObjectName
->Buffer
!= NULL
)
555 Status
= ObReferenceObjectByName(ObjectAttributes
->ObjectName
,
556 ObjectAttributes
->Attributes
,
563 if (Status
!= STATUS_SUCCESS
)
568 Status
= ObCreateHandle(PsGetCurrentProcess(),
573 ObDereferenceObject(Process
);
580 PLIST_ENTRY current_entry
;
584 KeAcquireSpinLock(&PsProcessListLock
, &oldIrql
);
585 current_entry
= PsProcessListHead
.Flink
;
586 while (current_entry
!= &PsProcessListHead
)
588 current
= CONTAINING_RECORD(current_entry
, EPROCESS
,
590 if (current
->UniqueProcessId
== (ULONG
)ClientId
->UniqueProcess
)
592 ObReferenceObjectByPointer(current
,
596 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
597 Status
= ObCreateHandle(PsGetCurrentProcess(),
602 ObDereferenceObject(current
);
603 DPRINT("*ProcessHandle %x\n", ProcessHandle
);
604 DPRINT("NtOpenProcess() = %x\n", Status
);
607 current_entry
= current_entry
->Flink
;
609 KeReleaseSpinLock(&PsProcessListLock
, oldIrql
);
610 DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
611 return(STATUS_UNSUCCESSFUL
);
613 return(STATUS_UNSUCCESSFUL
);
617 NTSTATUS STDCALL
NtQueryInformationProcess (IN HANDLE ProcessHandle
,
618 IN CINT ProcessInformationClass
,
619 OUT PVOID ProcessInformation
,
620 IN ULONG ProcessInformationLength
,
621 OUT PULONG ReturnLength
)
625 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
;
627 Status
= ObReferenceObjectByHandle(ProcessHandle
,
628 PROCESS_SET_INFORMATION
,
633 if (Status
!= STATUS_SUCCESS
)
638 switch (ProcessInformationClass
)
640 case ProcessBasicInformation
:
641 ProcessBasicInformationP
= (PPROCESS_BASIC_INFORMATION
)
643 ProcessBasicInformationP
->ExitStatus
= Process
->ExitStatus
;
644 ProcessBasicInformationP
->PebBaseAddress
= Process
->Peb
;
645 ProcessBasicInformationP
->AffinityMask
= Process
->Pcb
.Affinity
;
646 ProcessBasicInformationP
->UniqueProcessId
=
647 Process
->UniqueProcessId
;
648 ProcessBasicInformationP
->InheritedFromUniqueProcessId
=
649 Process
->InheritedFromUniqueProcessId
;
650 Status
= STATUS_SUCCESS
;
653 case ProcessQuotaLimits
:
654 case ProcessIoCounters
:
655 case ProcessVmCounters
:
657 case ProcessBasePriority
:
658 case ProcessRaisePriority
:
659 case ProcessDebugPort
:
660 case ProcessExceptionPort
:
661 case ProcessAccessToken
:
662 case ProcessLdtInformation
:
664 Status
= STATUS_NOT_IMPLEMENTED
;
667 case ProcessDefaultHardErrorMode
:
668 *((PULONG
)ProcessInformation
) = Process
->DefaultHardErrorProcessing
;
671 case ProcessIoPortHandlers
:
672 case ProcessWorkingSetWatch
:
673 case ProcessUserModeIOPL
:
674 case ProcessEnableAlignmentFaultFixup
:
675 case ProcessPriorityClass
:
676 case ProcessWx86Information
:
677 case ProcessHandleCount
:
678 case ProcessAffinityMask
:
680 Status
= STATUS_NOT_IMPLEMENTED
;
682 ObDereferenceObject(Process
);
686 NTSTATUS
PspAssignPrimaryToken(PEPROCESS Process
,
690 PACCESS_TOKEN OldToken
;
693 Status
= ObReferenceObjectByHandle(TokenHandle
,
699 if (!NT_SUCCESS(Status
))
703 Status
= SeExchangePrimaryToken(Process
, Token
, &OldToken
);
704 if (!NT_SUCCESS(Status
))
706 ObDereferenceObject(OldToken
);
708 ObDereferenceObject(Token
);
712 NTSTATUS STDCALL
NtSetInformationProcess(IN HANDLE ProcessHandle
,
713 IN CINT ProcessInformationClass
,
714 IN PVOID ProcessInformation
,
715 IN ULONG ProcessInformationLength
)
719 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP
;
720 PHANDLE ProcessAccessTokenP
;
722 Status
= ObReferenceObjectByHandle(ProcessHandle
,
723 PROCESS_SET_INFORMATION
,
728 if (!NT_SUCCESS(Status
))
733 switch (ProcessInformationClass
)
735 case ProcessBasicInformation
:
736 ProcessBasicInformationP
= (PPROCESS_BASIC_INFORMATION
)
738 memset(ProcessBasicInformationP
, 0, sizeof(PROCESS_BASIC_INFORMATION
));
739 Process
->Pcb
.Affinity
= ProcessBasicInformationP
->AffinityMask
;
740 Status
= STATUS_SUCCESS
;
743 case ProcessQuotaLimits
:
744 case ProcessIoCounters
:
745 case ProcessVmCounters
:
747 case ProcessBasePriority
:
748 case ProcessRaisePriority
:
749 case ProcessDebugPort
:
750 case ProcessExceptionPort
:
751 case ProcessAccessToken
:
752 ProcessAccessTokenP
= (PHANDLE
)ProcessInformation
;
753 Status
= PspAssignPrimaryToken(Process
, *ProcessAccessTokenP
);
756 case ProcessImageFileName
:
757 memcpy(Process
->ImageFileName
, ProcessInformation
, 8);
758 // DPRINT1("Process->ImageFileName %.8s\n", Process->ImageFileName);
759 Status
= STATUS_SUCCESS
;
762 case ProcessLdtInformation
:
764 case ProcessDefaultHardErrorMode
:
765 case ProcessIoPortHandlers
:
766 case ProcessWorkingSetWatch
:
767 case ProcessUserModeIOPL
:
768 case ProcessEnableAlignmentFaultFixup
:
769 case ProcessPriorityClass
:
770 case ProcessWx86Information
:
771 case ProcessHandleCount
:
772 case ProcessAffinityMask
:
774 Status
= STATUS_NOT_IMPLEMENTED
;
776 ObDereferenceObject(Process
);
782 /**********************************************************************
784 * PiSnapshotProcessTable
787 * Compute the size of a process+thread snapshot as
788 * expected by NtQuerySystemInformation.
791 * 0 on error; otherwise the size, in bytes of the buffer
792 * required to write a full snapshot.
795 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
799 PiSnapshotProcessTable (
800 IN PVOID SnapshotBuffer
,
802 IN PULONG pRequiredSize
806 PLIST_ENTRY CurrentEntryP
;
808 PLIST_ENTRY CurrentEntryT
;
811 ULONG RequiredSize
= 0L;
812 BOOLEAN SizeOnly
= FALSE
;
816 PSYSTEM_PROCESS_INFORMATION pInfoP
= (PSYSTEM_PROCESS_INFORMATION
) SnapshotBuffer
;
817 PSYSTEM_PROCESS_INFORMATION pInfoPLast
= NULL
;
818 PSYSTEM_THREAD_INFO pInfoT
= NULL
;
822 * Lock the process list.
829 * Scan the process list. Since the
830 * list is circular, the guard is false
831 * after the last process.
833 for ( CurrentEntryP
= PsProcessListHead
.Flink
;
834 (CurrentEntryP
!= & PsProcessListHead
);
835 CurrentEntryP
= CurrentEntryP
->Flink
839 * Compute how much space is
840 * occupied in the snapshot
841 * by adding this process info.
842 * (at least one thread).
844 SpiSizeCurrent
= sizeof (SYSTEM_PROCESS_INFORMATION
);
845 RequiredSize
+= SpiSizeCurrent
;
847 * Do not write process data in the
848 * buffer if it is too small.
850 if (TRUE
== SizeOnly
) continue;
852 * Check if the buffer can contain
855 if (Size
< RequiredSize
)
861 * Get a reference to the
862 * process descriptor we are
865 CurrentP
= CONTAINING_RECORD(
871 * Write process data in the buffer.
873 RtlZeroMemory (pInfoP
, sizeof (SYSTEM_PROCESS_INFORMATION
));
875 pInfoP
->ThreadCount
= 0L;
876 pInfoP
->ProcessId
= CurrentP
->UniqueProcessId
;
877 RtlInitUnicodeString (
879 CurrentP
->ImageFileName
882 for ( pInfoT
= & CurrentP
->ThreadSysInfo
[0],
883 CurrentEntryT
= CurrentP
->ThreadListHead
.Flink
;
885 (CurrentEntryT
!= & CurrentP
->ThreadListHead
);
887 pInfoT
= & CurrentP
->ThreadSysInfo
[pInfoP
->ThreadCount
],
888 CurrentEntryT
= CurrentEntryT
->Flink
892 * Recalculate the size of the
895 if (0 < pInfoP
->ThreadCount
)
897 RequiredSize
+= sizeof (SYSTEM_THREAD_INFORMATION
);
900 * Do not write thread data in the
901 * buffer if it is too small.
903 if (TRUE
== SizeOnly
) continue;
905 * Check if the buffer can contain
908 if (Size
< RequiredSize
)
914 * Get a reference to the
915 * thread descriptor we are
918 CurrentT
= CONTAINING_RECORD(
928 sizeof (SYSTEM_THREAD_INFORMATION
)
930 pInfoT
->KernelTime
= CurrentT
-> ; /* TIME */
931 pInfoT
->UserTime
= CurrentT
-> ; /* TIME */
932 pInfoT
->CreateTime
= CurrentT
-> ; /* TIME */
933 pInfoT
->TickCount
= CurrentT
-> ; /* ULONG */
934 pInfoT
->StartEIP
= CurrentT
-> ; /* ULONG */
935 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
936 pInfoT
->ClientId
= CurrentT
-> ; /* CLIENT_ID */
937 pInfoT
->DynamicPriority
= CurrentT
-> ; /* ULONG */
938 pInfoT
->BasePriority
= CurrentT
-> ; /* ULONG */
939 pInfoT
->nSwitches
= CurrentT
-> ; /* ULONG */
940 pInfoT
->State
= CurrentT
-> ; /* DWORD */
941 pInfoT
->WaitReason
= CurrentT
-> ; /* KWAIT_REASON */
943 * Count the number of threads
946 ++ pInfoP
->ThreadCount
;
949 * Save the size of information
950 * stored in the buffer for the
953 pInfoP
->RelativeOffset
= SpiSize
;
955 * Save a reference to the last
956 * valid information block.
960 * Compute the offset of the
961 * SYSTEM_PROCESS_INFORMATION
962 * descriptor in the snapshot
963 * buffer for the next process.
965 (ULONG
) pInfoP
+= SpiSize
;
968 * Unlock the process list.
975 * Return the proper error status code,
976 * if the buffer was too small.
978 if (TRUE
== SizeOnly
)
980 if (NULL
!= RequiredSize
)
982 *pRequiredSize
= RequiredSize
;
984 return STATUS_INFO_LENGTH_MISMATCH
;
987 * Mark the end of the snapshot.
989 pInfoP
->RelativeOffset
= 0L;
991 return STATUS_SUCCESS
;