ReactOS  r75907
state.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/ps/state.c
5  * PURPOSE: Process Manager: Process/Thread State Control
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  * Thomas Weidenmueller (w3seek@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* PRIVATE FUNCTIONS *********************************************************/
17 
18 VOID
19 NTAPI
21  IN OUT PKNORMAL_ROUTINE* NormalRoutine,
22  IN OUT PVOID* NormalContext,
25 {
26  /* Free the APC and do nothing else */
27  ExFreePool(Apc);
28 }
29 
31 NTAPI
33  OUT PULONG PreviousCount OPTIONAL)
34 {
35  ULONG OldCount;
36  PAGED_CODE();
37 
38  /* Resume the thread */
39  OldCount = KeResumeThread(&Thread->Tcb);
40 
41  /* Return the count if asked */
42  if (PreviousCount) *PreviousCount = OldCount;
43  return STATUS_SUCCESS;
44 }
45 
47 NTAPI
50  OUT PULONG PreviousCount OPTIONAL)
51 {
53  ULONG OldCount = 0;
54  PAGED_CODE();
55 
56  /* Assume success */
57  Status = STATUS_SUCCESS;
58 
59  /* Check if we're suspending ourselves */
60  if (Thread == PsGetCurrentThread())
61  {
62  /* Guard with SEH because KeSuspendThread can raise an exception */
63  _SEH2_TRY
64  {
65  /* Do the suspend */
66  OldCount = KeSuspendThread(&Thread->Tcb);
67  }
69  {
70  /* Get the exception code */
71  Status = _SEH2_GetExceptionCode();
72  }
73  _SEH2_END;
74  }
75  else
76  {
77  /* Acquire rundown protection */
78  if (ExAcquireRundownProtection(&Thread->RundownProtect))
79  {
80  /* Make sure the thread isn't terminating */
81  if (Thread->Terminated)
82  {
83  /* Fail */
85  }
86  else
87  {
88  /* Guard with SEH because KeSuspendThread can raise an exception */
89  _SEH2_TRY
90  {
91  /* Do the suspend */
92  OldCount = KeSuspendThread(&Thread->Tcb);
93  }
95  {
96  /* Get the exception code */
97  Status = _SEH2_GetExceptionCode();
98  }
99  _SEH2_END;
100 
101  /* Check if it was terminated during the suspend */
102  if (Thread->Terminated)
103  {
104  /* Wake it back up and fail */
105  KeForceResumeThread(&Thread->Tcb);
107  OldCount = 0;
108  }
109  }
110 
111  /* Release rundown protection */
112  ExReleaseRundownProtection(&Thread->RundownProtect);
113  }
114  else
115  {
116  /* Thread is terminating */
118  }
119  }
120 
121  /* Write back the previous count */
122  if (PreviousCount) *PreviousCount = OldCount;
123  return Status;
124 }
125 
126 NTSTATUS
127 NTAPI
129 {
131  PAGED_CODE();
132 
133  /* Lock the Process */
134  if (!ExAcquireRundownProtection(&Process->RundownProtect))
135  {
136  /* Process is terminating */
138  }
139 
140  /* Get the first thread */
141  Thread = PsGetNextProcessThread(Process, NULL);
142  while (Thread)
143  {
144  /* Resume it */
145  KeResumeThread(&Thread->Tcb);
146 
147  /* Move to the next thread */
148  Thread = PsGetNextProcessThread(Process, Thread);
149  }
150 
151  /* Unlock the process */
152  ExReleaseRundownProtection(&Process->RundownProtect);
153  return STATUS_SUCCESS;
154 }
155 
156 NTSTATUS
157 NTAPI
159 {
161  PAGED_CODE();
162 
163  /* Lock the Process */
164  if (!ExAcquireRundownProtection(&Process->RundownProtect))
165  {
166  /* Process is terminating */
168  }
169 
170  /* Get the first thread */
171  Thread = PsGetNextProcessThread(Process, NULL);
172  while (Thread)
173  {
174  /* Resume it */
175  PsSuspendThread(Thread, NULL);
176 
177  /* Move to the next thread */
178  Thread = PsGetNextProcessThread(Process, Thread);
179  }
180 
181  /* Unlock the process */
182  ExReleaseRundownProtection(&Process->RundownProtect);
183  return STATUS_SUCCESS;
184 }
185 
186 /* PUBLIC FUNCTIONS **********************************************************/
187 
188 /*
189  * @implemented
190  */
191 NTSTATUS
192 NTAPI
193 NtAlertThread(IN HANDLE ThreadHandle)
194 {
198 
199  /* Reference the Object */
200  Status = ObReferenceObjectByHandle(ThreadHandle,
202  PsThreadType,
203  PreviousMode,
204  (PVOID*)&Thread,
205  NULL);
206  if (NT_SUCCESS(Status))
207  {
208  /*
209  * Do an alert depending on the processor mode. If some kmode code wants to
210  * enforce a umode alert it should call KeAlertThread() directly. If kmode
211  * code wants to do a kmode alert it's sufficient to call it with Zw or just
212  * use KeAlertThread() directly
213  */
214  KeAlertThread(&Thread->Tcb, PreviousMode);
215 
216  /* Dereference Object */
217  ObDereferenceObject(Thread);
218  }
219 
220  /* Return status */
221  return Status;
222 }
223 
224 NTSTATUS
225 NTAPI
227  OUT PULONG SuspendCount)
228 {
233 
234  /* Check if we came from user mode with a suspend count */
235  if ((SuspendCount) && (PreviousMode != KernelMode))
236  {
237  /* Enter SEH for probing */
238  _SEH2_TRY
239  {
240  /* Probe the count */
241  ProbeForWriteUlong(SuspendCount);
242  }
244  {
245  /* Return the exception code */
247  }
248  _SEH2_END;
249  }
250 
251  /* Reference the Object */
252  Status = ObReferenceObjectByHandle(ThreadHandle,
254  PsThreadType,
255  PreviousMode,
256  (PVOID*)&Thread,
257  NULL);
258  if (NT_SUCCESS(Status))
259  {
260  /* Call the Kernel Function */
261  PreviousState = KeAlertResumeThread(&Thread->Tcb);
262 
263  /* Dereference Object */
264  ObDereferenceObject(Thread);
265 
266  /* Check if the caller gave a suspend count */
267  if (SuspendCount)
268  {
269  /* Enter SEH for write */
270  _SEH2_TRY
271  {
272  /* Write state back */
273  *SuspendCount = PreviousState;
274  }
276  {
277  /* Get exception code */
278  Status = _SEH2_GetExceptionCode();
279  }
280  _SEH2_END;
281  }
282  }
283 
284  /* Return status */
285  return Status;
286 }
287 
288 NTSTATUS
289 NTAPI
290 NtResumeThread(IN HANDLE ThreadHandle,
291  OUT PULONG SuspendCount OPTIONAL)
292 {
294  ULONG Prev;
297  PAGED_CODE();
298 
299  /* Check if caller gave a suspend count from user mode */
300  if ((SuspendCount) && (PreviousMode != KernelMode))
301  {
302  /* Enter SEH for probing */
303  _SEH2_TRY
304  {
305  /* Probe the count */
306  ProbeForWriteUlong(SuspendCount);
307  }
309  {
310  /* Return the exception code */
312  }
313  _SEH2_END;
314  }
315 
316  /* Get the Thread Object */
317  Status = ObReferenceObjectByHandle(ThreadHandle,
319  PsThreadType,
320  PreviousMode,
321  (PVOID*)&Thread,
322  NULL);
323  if (!NT_SUCCESS(Status)) return Status;
324 
325  /* Call the internal function */
326  Status = PsResumeThread(Thread, &Prev);
327 
328  /* Check if the caller wanted the count back */
329  if (SuspendCount)
330  {
331  /* Enter SEH for write back */
332  _SEH2_TRY
333  {
334  /* Write the count */
335  *SuspendCount = Prev;
336  }
338  {
339  /* Get the exception code */
340  Status = _SEH2_GetExceptionCode();
341  }
342  _SEH2_END;
343  }
344 
345  /* Dereference and return */
346  ObDereferenceObject(Thread);
347  return Status;
348 }
349 
350 NTSTATUS
351 NTAPI
352 NtSuspendThread(IN HANDLE ThreadHandle,
353  OUT PULONG PreviousSuspendCount OPTIONAL)
354 {
356  ULONG Prev;
359  PAGED_CODE();
360 
361  /* Check if caller gave a suspend count from user mode */
362  if ((PreviousSuspendCount) && (PreviousMode != KernelMode))
363  {
364  /* Enter SEH for probing */
365  _SEH2_TRY
366  {
367  /* Probe the count */
368  ProbeForWriteUlong(PreviousSuspendCount);
369  }
371  {
372  /* Return the exception code */
374  }
375  _SEH2_END;
376  }
377 
378  /* Get the Thread Object */
379  Status = ObReferenceObjectByHandle(ThreadHandle,
381  PsThreadType,
382  PreviousMode,
383  (PVOID*)&Thread,
384  NULL);
385  if (!NT_SUCCESS(Status)) return Status;
386 
387  /* Call the internal function */
388  Status = PsSuspendThread(Thread, &Prev);
389  ObDereferenceObject(Thread);
390  if (!NT_SUCCESS(Status)) return Status;
391 
392  /* Protect write with SEH */
393  _SEH2_TRY
394  {
395  /* Return the Previous Count */
396  if (PreviousSuspendCount) *PreviousSuspendCount = Prev;
397  }
399  {
400  /* Get the exception code */
401  Status = _SEH2_GetExceptionCode();
402  }
403  _SEH2_END;
404 
405  /* Return */
406  return Status;
407 }
408 
409 NTSTATUS
410 NTAPI
412 {
416  PAGED_CODE();
417 
418  /* Reference the process */
419  Status = ObReferenceObjectByHandle(ProcessHandle,
422  PreviousMode,
423  (PVOID*)&Process,
424  NULL);
425  if (NT_SUCCESS(Status))
426  {
427  /* Call the internal function */
428  Status = PsSuspendProcess(Process);
429  ObDereferenceObject(Process);
430  }
431 
432  /* Return status */
433  return Status;
434 }
435 
436 NTSTATUS
437 NTAPI
439 {
443  PAGED_CODE();
444 
445  /* Reference the process */
446  Status = ObReferenceObjectByHandle(ProcessHandle,
449  PreviousMode,
450  (PVOID*)&Process,
451  NULL);
452  if (NT_SUCCESS(Status))
453  {
454  /* Call the internal function */
455  Status = PsResumeProcess(Process);
456  ObDereferenceObject(Process);
457  }
458 
459  /* Return status */
460  return Status;
461 }
462 
463 NTSTATUS
464 NTAPI
466 {
467  /* Check and Alert Thread if needed */
470 }
471 
472 /*++
473  * @name NtQueueApcThread
474  * NT4
475  *
476  * This routine is used to queue an APC from user-mode for the specified
477  * thread.
478  *
479  * @param ThreadHandle
480  * Handle to the Thread.
481  * This handle must have THREAD_SET_CONTEXT privileges.
482  *
483  * @param ApcRoutine
484  * Pointer to the APC Routine to call when the APC executes.
485  *
486  * @param NormalContext
487  * Pointer to the context to send to the Normal Routine.
488  *
489  * @param SystemArgument[1-2]
490  * Pointer to a set of two parameters that contain untyped data.
491  *
492  * @return STATUS_SUCCESS or failure cute from associated calls.
493  *
494  * @remarks The thread must enter an alertable wait before the APC will be
495  * delivered.
496  *
497  *--*/
498 NTSTATUS
499 NTAPI
502  IN PVOID NormalContext,
505 {
506  PKAPC Apc;
509  PAGED_CODE();
510 
511  /* Get ETHREAD from Handle */
512  Status = ObReferenceObjectByHandle(ThreadHandle,
514  PsThreadType,
516  (PVOID)&Thread,
517  NULL);
518  if (!NT_SUCCESS(Status)) return Status;
519 
520  /* Check if this is a System Thread */
521  if (Thread->SystemThread)
522  {
523  /* Fail */
524  Status = STATUS_INVALID_HANDLE;
525  goto Quit;
526  }
527 
528  /* Allocate an APC */
531  sizeof(KAPC),
532  TAG_PS_APC);
533  if (!Apc)
534  {
535  /* Fail */
536  Status = STATUS_NO_MEMORY;
537  goto Quit;
538  }
539 
540  /* Initialize the APC */
541  KeInitializeApc(Apc,
542  &Thread->Tcb,
545  NULL,
546  ApcRoutine,
547  UserMode,
548  NormalContext);
549 
550  /* Queue it */
551  if (!KeInsertQueueApc(Apc,
552  SystemArgument1,
553  SystemArgument2,
555  {
556  /* We failed, free it */
557  ExFreePool(Apc);
558  Status = STATUS_UNSUCCESSFUL;
559  }
560 
561  /* Dereference Thread and Return */
562 Quit:
563  ObDereferenceObject(Thread);
564  return Status;
565 }
566 
567 /* EOF */
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
DWORD *typedef PVOID
Definition: winlogon.h:52
VOID NTAPI KeInitializeApc(IN PKAPC Apc, IN PKTHREAD Thread, IN KAPC_ENVIRONMENT TargetEnvironment, IN PKKERNEL_ROUTINE KernelRoutine, IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, IN PKNORMAL_ROUTINE NormalRoutine, IN KPROCESSOR_MODE Mode, IN PVOID Context)
Definition: apc.c:651
#define IN
Definition: typedefs.h:39
ULONG NTAPI KeAlertResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:133
PVOID NTAPI ExAllocatePoolWithQuotaTag(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, IN ULONG Tag)
Definition: expool.c:2611
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
NTSTATUS NTAPI NtSuspendProcess(IN HANDLE ProcessHandle)
Definition: state.c:411
NTKERNELAPI VOID FASTCALL ExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RunRef)
#define STATUS_THREAD_IS_TERMINATING
Definition: ntstatus.h:297
return STATUS_SUCCESS
Definition: btrfs.c:2664
ULONG NTAPI KeResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:397
KTHREAD Tcb
Definition: pstypes.h:1035
#define ExAcquireRundownProtection
Definition: ex.h:120
NTSTATUS NTAPI NtAlertThread(IN HANDLE ThreadHandle)
Definition: state.c:193
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:2740
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:267
NTSTATUS NTAPI NtSuspendThread(IN HANDLE ThreadHandle, OUT PULONG PreviousSuspendCount OPTIONAL)
Definition: state.c:352
#define THREAD_SUSPEND_RESUME
#define STATUS_ALERTED
Definition: ntstatus.h:80
NTSTATUS NTAPI NtQueueApcThread(IN HANDLE ThreadHandle, IN PKNORMAL_ROUTINE ApcRoutine, IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: state.c:500
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:231
#define TAG_PS_APC
Definition: tag.h:167
ULONG NTAPI KeSuspendThread(PKTHREAD Thread)
Definition: thrdobj.c:610
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:388
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
VOID NTAPI PspQueueApcSpecialApc(IN PKAPC Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2)
Definition: state.c:20
NTSTATUS NTAPI NtResumeProcess(IN HANDLE ProcessHandle)
Definition: state.c:438
#define _SEH2_END
Definition: pseh2_64.h:7
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
smooth NULL
Definition: ftsmooth.c:513
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:660
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
NTSTATUS NTAPI NtResumeThread(IN HANDLE ThreadHandle, OUT PULONG SuspendCount OPTIONAL)
Definition: state.c:290
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:488
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
BOOLEAN NTAPI KeAlertThread(IN PKTHREAD Thread, IN KPROCESSOR_MODE AlertMode)
Definition: thrdobj.c:185
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:632
#define PAGED_CODE()
Definition: video.h:57
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_opt_ HANDLE _In_opt_ PIO_APC_ROUTINE ApcRoutine
Definition: iofuncs.h:719
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
PETHREAD NTAPI PsGetNextProcessThread(IN PEPROCESS Process, IN PETHREAD Thread OPTIONAL)
Definition: process.c:75
POBJECT_TYPE PsThreadType
Definition: thread.c:20
NTSTATUS NTAPI NtAlertResumeThread(IN HANDLE ThreadHandle, OUT PULONG SuspendCount)
Definition: state.c:226
Definition: ketypes.h:520
#define PROCESS_SUSPEND_RESUME
Definition: pstypes.h:160
Status
Definition: gdiplustypes.h:24
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:660
_In_ PLARGE_INTEGER _In_opt_ PTIMER_APC_ROUTINE _In_opt_ PVOID _In_ BOOLEAN _In_opt_ LONG _Out_opt_ PBOOLEAN PreviousState
Definition: zwfuncs.h:428
#define NT_SUCCESS(StatCode)
Definition: cmd.c:149
NTSTATUS NTAPI PsResumeProcess(IN PEPROCESS Process)
Definition: state.c:128
DWORD *typedef HANDLE
Definition: winlogon.h:52
LONG NTSTATUS
Definition: DriverTester.h:11
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define _SEH2_TRY
Definition: pseh2_64.h:5
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI PsSuspendProcess(IN PEPROCESS Process)
Definition: state.c:158
BOOLEAN NTAPI KeInsertQueueApc(IN PKAPC Apc, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN KPRIORITY PriorityBoost)
Definition: apc.c:735
NTSTATUS NTAPI NtTestAlert(VOID)
Definition: state.c:465
BOOLEAN NTAPI KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
Definition: thrdobj.c:731
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
#define THREAD_SET_CONTEXT
#define OUT
Definition: typedefs.h:40
ULONG NTAPI KeForceResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:276
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
_In_ HANDLE ProcessHandle
Definition: mmfuncs.h:403
#define STATUS_SUSPEND_COUNT_EXCEEDED
Definition: ntstatus.h:296
POBJECT_TYPE PsProcessType
Definition: process.c:20
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
NTSTATUS NTAPI PsSuspendThread(IN PETHREAD Thread, OUT PULONG PreviousCount OPTIONAL)
Definition: state.c:48
NTSTATUS NTAPI PsResumeThread(IN PETHREAD Thread, OUT PULONG PreviousCount OPTIONAL)
Definition: state.c:32