:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / lib / psapi / enum / process.c
1 /* $Id$
2 */
3 /*
4  * COPYRIGHT:   See COPYING in the top level directory
5  * LICENSE:     See LGPL.txt in the top level directory
6  * PROJECT:     ReactOS system libraries
7  * FILE:        reactos/lib/psapi/enum/process.c
8  * PURPOSE:     Enumerate processes
9  * PROGRAMMER:  KJK::Hyperion <noog@libero.it>
10  * UPDATE HISTORY:
11  *              10/06/2002: Created
12  *              29/08/2002: Generalized the interface to improve reusability,
13  *                          more efficient use of memory operations
14  */
15
16 #include <stdlib.h>
17 #include <ddk/ntddk.h>
18 #include <debug.h>
19 #include <internal/psapi.h>
20
21 NTSTATUS
22 STDCALL
23 PsaEnumerateProcesses
24 (
25  IN PPROC_ENUM_ROUTINE Callback,
26  IN OUT PVOID CallbackContext
27 )
28 {
29  register NTSTATUS nErrCode = STATUS_SUCCESS;
30  PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL;
31  PSYSTEM_PROCESS_INFORMATION pInfoHead = NULL;
32  ULONG nSize = 32768;
33
34  /* FIXME: if the system has loaded several processes and threads, the buffer
35     could get really big. But if there's several processes and threads, the
36     system is already under stress, and a huge buffer could only make things
37     worse. The function should be profiled to see what's the average minimum
38     buffer size, to succeed on the first shot */
39  do
40  {
41   void * pTmp;
42   
43   /* free the buffer, and reallocate it to the new size. RATIONALE: since we
44      ignore the buffer's contents at this point, there's no point in a realloc()
45      that could end up copying a large chunk of data we'd discard anyway */
46   free(pInfoBuffer);
47   pTmp = malloc(nSize);
48   
49   if(pTmp == NULL)
50   {
51    /* failure */
52    DPRINT(FAILED_WITH_STATUS, "malloc", STATUS_NO_MEMORY);
53    nErrCode = STATUS_NO_MEMORY;
54    goto esp_Finalize;
55   }
56   
57   pInfoBuffer = pTmp;
58   
59   /* query the information */
60   nErrCode = NtQuerySystemInformation
61   (
62    SystemProcessesAndThreadsInformation,
63    pInfoBuffer,
64    nSize,
65    NULL
66   );
67
68   /* double the buffer size */
69   nSize += nSize;
70  }
71  /* repeat until the buffer is big enough */
72  while(nErrCode == STATUS_INFO_LENGTH_MISMATCH);
73  
74  /* failure */
75  if(!NT_SUCCESS(nErrCode))
76  {
77   DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode);
78   goto esp_Finalize;
79  }
80  
81  /* list head */
82  pInfoHead = pInfoBuffer;
83
84  /* scan the list */
85  while(1)
86  {
87   /* notify the callback */
88   nErrCode = Callback(pInfoHead, CallbackContext);
89
90   /* if the callback returned an error or this is the end of the process list,
91      break out */
92   if(!NT_SUCCESS(nErrCode) || pInfoHead->RelativeOffset == 0)
93    break;
94   
95   /* move to the next process */
96   pInfoHead = 
97    (SYSTEM_PROCESS_INFORMATION*)
98    ((ULONG)pInfoHead + pInfoHead->RelativeOffset);
99  }
100
101 esp_Finalize:
102  /* free the buffer */
103  free(pInfoBuffer);
104  
105  /* return the last status */
106  return (nErrCode);
107 }
108
109 /* EOF */
110