Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
13 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. psenum.c
  5. Abstract:
  6. This module enumerates the actve processes in the system
  7. Author:
  8. Neill clift (NeillC) 23-Mar-2000
  9. Revision History:
  10. --*/
  11. #include "psp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, PsEnumProcesses)
  14. #pragma alloc_text(PAGE, PsGetNextProcess)
  15. #pragma alloc_text(PAGE, PsQuitNextProcess)
  16. #pragma alloc_text(PAGE, PsEnumProcessThreads)
  17. #pragma alloc_text(PAGE, PsGetNextProcessThread)
  18. #pragma alloc_text(PAGE, PsQuitNextProcessThread)
  19. #pragma alloc_text(PAGE, PsGetNextJob)
  20. #pragma alloc_text(PAGE, PsGetNextJobProcess)
  21. #pragma alloc_text(PAGE, PsQuitNextJob)
  22. #pragma alloc_text(PAGE, PsQuitNextJobProcess)
  23. #pragma alloc_text(PAGE, PspGetNextJobProcess)
  24. #pragma alloc_text(PAGE, PspQuitNextJobProcess)
  25. #endif
  26. NTSTATUS
  27. PsEnumProcesses (
  28. IN PROCESS_ENUM_ROUTINE CallBack,
  29. IN PVOID Context
  30. )
  31. /*++
  32. Routine Description:
  33. This function calls the callback routine for each active process in the system.
  34. Process objects in the process of being deleted are skipped.
  35. Returning anything but a success code from the callback routine terminates the enumeration at that point.
  36. Processes may be referenced and used later safely.
  37. Arguments:
  38. CallBack - Routine to be called with its first parameter the enumerated process
  39. Return Value:
  40. NTSTATUS - Status of call
  41. --*/
  42. {
  43. PLIST_ENTRY ListEntry;
  44. PEPROCESS Process, NewProcess;
  45. PETHREAD CurrentThread;
  46. NTSTATUS Status;
  47. Process = NULL;
  48. CurrentThread = PsGetCurrentThread ();
  49. PspLockProcessList(CurrentThread);
  50. for (ListEntry = PsActiveProcessHead.Flink;
  51. ListEntry != &PsActiveProcessHead;
  52. ListEntry = ListEntry->Flink) {
  53. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, ActiveProcessLinks);
  54. if (ObReferenceObjectSafe (NewProcess)) {
  55. PspUnlockProcessList(CurrentThread);
  56. if (Process != NULL) {
  57. ObDereferenceObject (Process);
  58. }
  59. Process = NewProcess;
  60. Status = CallBack (Process, Context);
  61. if (!NT_SUCCESS (Status)) {
  62. ObDereferenceObject (Process);
  63. return Status;
  64. }
  65. PspLockProcessList(CurrentThread);
  66. }
  67. }
  68. PspUnlockProcessList(CurrentThread);
  69. if (Process != NULL) {
  70. ObDereferenceObject (Process);
  71. }
  72. return STATUS_SUCCESS;
  73. }
  74. PEPROCESS
  75. PsGetNextProcess (
  76. IN PEPROCESS Process
  77. )
  78. /*++
  79. Routine Description:
  80. This function allows code to enumerate all the active processes in the system.
  81. The first process (if Process is NULL) or subsequent process (if process not NULL) is returned on
  82. each call.
  83. If process is not NULL then this process must have previously been obtained by a call to PsGetNextProcess.
  84. Enumeration may be terminated early by calling PsQuitNextProcess on the last non-NULL process
  85. returned by PsGetNextProcess.
  86. Processes may be referenced and used later safely.
  87. For example, to enumerate all system processes in a loop use this code fragment:
  88. for (Process = PsGetNextProcess (NULL);
  89. Process != NULL;
  90. Process = PsGetNextProcess (Process)) {
  91. ...
  92. ...
  93. //
  94. // Early terminating conditions are handled like this:
  95. //
  96. if (NeedToBreakOutEarly) {
  97. PsQuitNextProcess (Process);
  98. break;
  99. }
  100. }
  101. Arguments:
  102. Process - Process to get the next process from or NULL for the first process
  103. Return Value:
  104. PEPROCESS - Next process or NULL if no more processes available
  105. --*/
  106. {
  107. PEPROCESS NewProcess = NULL;
  108. PETHREAD CurrentThread;
  109. PLIST_ENTRY ListEntry;
  110. CurrentThread = PsGetCurrentThread ();
  111. PspLockProcessList (CurrentThread);
  112. for (ListEntry = (Process == NULL) ? PsActiveProcessHead.Flink : Process->ActiveProcessLinks.Flink;
  113. ListEntry != &PsActiveProcessHead;
  114. ListEntry = ListEntry->Flink) {
  115. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, ActiveProcessLinks);
  116. //
  117. // Processes are removed from this list during process objected deletion (object reference count goes
  118. // to zero). To prevent double deletion of the process we need to do a safe reference here.
  119. //
  120. if (ObReferenceObjectSafe (NewProcess)) {
  121. break;
  122. }
  123. NewProcess = NULL;
  124. }
  125. PspUnlockProcessList (CurrentThread);
  126. if (Process != NULL) {
  127. ObDereferenceObject (Process);
  128. }
  129. return NewProcess;
  130. }
  131. VOID
  132. PsQuitNextProcess (
  133. IN PEPROCESS Process
  134. )
  135. /*++
  136. Routine Description:
  137. This function is used to terminate early a process enumeration using PsGetNextProcess
  138. Arguments:
  139. Process - Non-NULL process previously obtained by a call to PsGetNextProcess.
  140. Return Value:
  141. None
  142. --*/
  143. {
  144. ObDereferenceObject (Process);
  145. }
  146. PETHREAD
  147. PsGetNextProcessThread (
  148. IN PEPROCESS Process,
  149. IN PETHREAD Thread
  150. )
  151. /*++
  152. Routine Description:
  153. This function is used to enumerate the threads in a process.
  154. Arguments:
  155. Process - Process to enumerate
  156. Thread - Thread to start enumeration from. This must have been obtained from previous call to
  157. PsGetNextProcessThread. If NULL enumeration starts at the first non-terminating thread in the process.
  158. Return Value:
  159. PETHREAD - Pointer to a non-terminated process thread or a NULL if there are non. This thread must be passed
  160. either to another call to PsGetNextProcessThread or PsQuitNextProcessThread.
  161. --*/
  162. {
  163. PLIST_ENTRY ListEntry;
  164. PETHREAD NewThread, CurrentThread;
  165. PAGED_CODE ();
  166. CurrentThread = PsGetCurrentThread ();
  167. PspLockProcessShared (Process, CurrentThread);
  168. for (ListEntry = (Thread == NULL) ? Process->ThreadListHead.Flink : Thread->ThreadListEntry.Flink;
  169. ;
  170. ListEntry = ListEntry->Flink) {
  171. if (ListEntry != &Process->ThreadListHead) {
  172. NewThread = CONTAINING_RECORD (ListEntry, ETHREAD, ThreadListEntry);
  173. //
  174. // Don't reference a thread thats in its delete routine
  175. //
  176. if (ObReferenceObjectSafe (NewThread)) {
  177. break;
  178. }
  179. } else {
  180. NewThread = NULL;
  181. break;
  182. }
  183. }
  184. PspUnlockProcessShared (Process, CurrentThread);
  185. if (Thread != NULL) {
  186. ObDereferenceObject (Thread);
  187. }
  188. return NewThread;
  189. }
  190. VOID
  191. PsQuitNextProcessThread (
  192. IN PETHREAD Thread
  193. )
  194. /*++
  195. Routine Description:
  196. This function quits thread enumeration early.
  197. Arguments:
  198. Thread - Thread obtained from a call to PsGetNextProcessThread
  199. Return Value:
  200. None.
  201. --*/
  202. {
  203. ObDereferenceObject (Thread);
  204. }
  205. NTSTATUS
  206. PsEnumProcessThreads (
  207. IN PEPROCESS Process,
  208. IN THREAD_ENUM_ROUTINE CallBack,
  209. IN PVOID Context
  210. )
  211. /*++
  212. Routine Description:
  213. This function calls the callback routine for each active thread in the process.
  214. Thread objects in the process of being deleted are skipped.
  215. Returning anything but a success code from the callback routine terminates the enumeration at that point.
  216. Thread may be referenced and used later safely.
  217. Arguments:
  218. CallBack - Routine to be called with its first parameter the enumerated process
  219. Return Value:
  220. NTSTATUS - Status of call
  221. --*/
  222. {
  223. NTSTATUS Status;
  224. PETHREAD Thread;
  225. Status = STATUS_SUCCESS;
  226. for (Thread = PsGetNextProcessThread (Process, NULL);
  227. Thread != NULL;
  228. Thread = PsGetNextProcessThread (Process, Thread)) {
  229. Status = CallBack (Process, Thread, Context);
  230. if (!NT_SUCCESS (Status)) {
  231. PsQuitNextProcessThread (Thread);
  232. break;
  233. }
  234. }
  235. return Status;
  236. }
  237. PEJOB
  238. PsGetNextJob (
  239. IN PEJOB Job
  240. )
  241. /*++
  242. Routine Description:
  243. This function allows code to enumerate all the active jobs in the system.
  244. The first job (if Job is NULL) or subsequent jobs (if Job not NULL) is returned on
  245. each call.
  246. If Job is not NULL then this job must have previously been obtained by a call to PsGetNextJob.
  247. Enumeration may be terminated early by calling PsQuitNextJob on the last non-NULL job
  248. returned by PsGetNextJob.
  249. Jobs may be referenced and used later safely.
  250. For example, to enumerate all system jobs in a loop use this code fragment:
  251. for (Job = PsGetNextJob (NULL);
  252. Job != NULL;
  253. Job = PsGetNextJob (Job)) {
  254. ...
  255. ...
  256. //
  257. // Early terminating conditions are handled like this:
  258. //
  259. if (NeedToBreakOutEarly) {
  260. PsQuitNextJob (Job);
  261. break;
  262. }
  263. }
  264. Arguments:
  265. Job - Job from a previous call to PsGetNextJob or NULL for the first job in the system
  266. Return Value:
  267. PEJOB - Next job in the system or NULL if none available.
  268. --*/
  269. {
  270. PEJOB NewJob = NULL;
  271. PLIST_ENTRY ListEntry;
  272. ExAcquireFastMutex (&PspJobListLock);
  273. for (ListEntry = (Job == NULL) ? PspJobList.Flink : Job->JobLinks.Flink;
  274. ListEntry != &PspJobList;
  275. ListEntry = ListEntry->Flink) {
  276. NewJob = CONTAINING_RECORD (ListEntry, EJOB, JobLinks);
  277. //
  278. // Jobs are removed from this list during job objected deletion (object reference count goes
  279. // to zero). To prevent double deletion of the job we need to do a safe reference here.
  280. //
  281. if (ObReferenceObjectSafe (NewJob)) {
  282. break;
  283. }
  284. NewJob = NULL;
  285. }
  286. ExReleaseFastMutex (&PspJobListLock);
  287. if (Job != NULL) {
  288. ObDereferenceObject (Job);
  289. }
  290. return NewJob;
  291. }
  292. VOID
  293. PsQuitNextJob (
  294. IN PEJOB Job
  295. )
  296. /*++
  297. Routine Description:
  298. This function is used to terminate early a job enumeration using PsGetNextJob
  299. Arguments:
  300. Job - Non-NULL job previously obtained by a call to PsGetNextJob.
  301. Return Value:
  302. None
  303. --*/
  304. {
  305. ObDereferenceObject (Job);
  306. }
  307. PEPROCESS
  308. PsGetNextJobProcess (
  309. IN PEJOB Job,
  310. IN PEPROCESS Process
  311. )
  312. /*++
  313. Routine Description:
  314. This function is used to enumerate the processes in a job.
  315. Arguments:
  316. Job - Job to Enumerate
  317. Process - Process to start enumeration from. This must have been obtained from previous call to
  318. PsGetNextJobProcess. If NULL enumeration starts at the first non-terminating process in the Job.
  319. Return Value:
  320. PEPROCESS - Pointer to a non-terminated process or a NULL if there are non. This process must be passed
  321. either to another call to PsGetNextJobProcess or PsQuitNextJobProcess.
  322. --*/
  323. {
  324. PLIST_ENTRY ListEntry;
  325. PEPROCESS NewProcess;
  326. PETHREAD CurrentThread;
  327. PAGED_CODE ();
  328. CurrentThread = PsGetCurrentThread ();
  329. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  330. ExAcquireResourceExclusiveLite (&Job->JobLock, TRUE);
  331. for (ListEntry = (Process == NULL) ? Job->ProcessListHead.Flink : Process->JobLinks.Flink;
  332. ;
  333. ListEntry = ListEntry->Flink) {
  334. if (ListEntry != &Job->ProcessListHead) {
  335. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, JobLinks);
  336. //
  337. // Don't reference a process thats in its delete routine
  338. //
  339. if (ObReferenceObjectSafe (NewProcess)) {
  340. break;
  341. }
  342. } else {
  343. NewProcess = NULL;
  344. break;
  345. }
  346. }
  347. ExReleaseResourceLite (&Job->JobLock);
  348. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  349. if (Process != NULL) {
  350. ObDereferenceObject (Process);
  351. }
  352. return NewProcess;
  353. }
  354. VOID
  355. PsQuitNextJobProcess (
  356. IN PEPROCESS Process
  357. )
  358. /*++
  359. Routine Description:
  360. This function quits job process enumeration early.
  361. Arguments:
  362. Process - Process obtained from a call to PsGetNextJobProcess
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. ObDereferenceObject (Process);
  368. }
  369. PEPROCESS
  370. PspGetNextJobProcess (
  371. IN PEJOB Job,
  372. IN PEPROCESS Process
  373. )
  374. /*++
  375. Routine Description:
  376. This function is used to enumerate the processes in a job with the job lock held.
  377. Arguments:
  378. Job - Job to Enumerate
  379. Process - Process to start enumeration from. This must have been obtained from previous call to
  380. PsGetNextJobProcess. If NULL enumeration starts at the first non-terminating process in the Job.
  381. Return Value:
  382. PEPROCESS - Pointer to a non-terminated process or a NULL if there are non. This process must be passed
  383. either to another call to PsGetNextJobProcess or PsQuitNextJobProcess.
  384. --*/
  385. {
  386. PLIST_ENTRY ListEntry;
  387. PEPROCESS NewProcess;
  388. PAGED_CODE ();
  389. for (ListEntry = (Process == NULL) ? Job->ProcessListHead.Flink : Process->JobLinks.Flink;
  390. ;
  391. ListEntry = ListEntry->Flink) {
  392. if (ListEntry != &Job->ProcessListHead) {
  393. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, JobLinks);
  394. //
  395. // Don't reference a process thats in its delete routine
  396. //
  397. if (ObReferenceObjectSafe (NewProcess)) {
  398. break;
  399. }
  400. } else {
  401. NewProcess = NULL;
  402. break;
  403. }
  404. }
  405. if (Process != NULL) {
  406. ObDereferenceObjectDeferDelete (Process);
  407. }
  408. return NewProcess;
  409. }
  410. VOID
  411. PspQuitNextJobProcess (
  412. IN PEPROCESS Process
  413. )
  414. /*++
  415. Routine Description:
  416. This function quits job process enumeration early.
  417. Arguments:
  418. Process - Process obtained from a call to PsGetNextJobProcess
  419. Return Value:
  420. None.
  421. --*/
  422. {
  423. ObDereferenceObjectDeferDelete (Process);
  424. }