ReactOS  0.4.14-dev-49-gfb4591c
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 */
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 */
72  }
73  _SEH2_END;
74  }
75  else
76  {
77  /* Acquire rundown protection */
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 */
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 */
107  OldCount = 0;
108  }
109  }
110 
111  /* Release rundown protection */
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 */
142  while (Thread)
143  {
144  /* Resume it */
146 
147  /* Move to the next 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 */
172  while (Thread)
173  {
174  /* Resume it */
176 
177  /* Move to the next 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  */
215 
216  /* Dereference Object */
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 */
262 
263  /* Dereference Object */
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 */
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 */
341  }
342  _SEH2_END;
343  }
344 
345  /* Dereference and return */
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);
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 */
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 */
422  PreviousMode,
423  (PVOID*)&Process,
424  NULL);
425  if (NT_SUCCESS(Status))
426  {
427  /* Call the internal function */
430  }
431 
432  /* Return status */
433  return Status;
434 }
435 
436 NTSTATUS
437 NTAPI
439 {
443  PAGED_CODE();
444 
445  /* Reference the process */
449  PreviousMode,
450  (PVOID*)&Process,
451  NULL);
452  if (NT_SUCCESS(Status))
453  {
454  /* Call the internal function */
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 NtQueueApcThreadEx
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 UserApcReserveHandle
484  * Optional handle to reserve object (introduced in Windows 7), providing ability to
485  * reserve memory before performing stability-critical parts of code.
486  *
487  * @param ApcRoutine
488  * Pointer to the APC Routine to call when the APC executes.
489  *
490  * @param NormalContext
491  * Pointer to the context to send to the Normal Routine.
492  *
493  * @param SystemArgument[1-2]
494  * Pointer to a set of two parameters that contain untyped data.
495  *
496  * @return STATUS_SUCCESS or failure cute from associated calls.
497  *
498  * @remarks The thread must enter an alertable wait before the APC will be
499  * delivered.
500  *
501  *--*/
502 NTSTATUS
503 NTAPI
505  IN OPTIONAL HANDLE UserApcReserveHandle,
507  IN PVOID NormalContext,
510 {
511  PKAPC Apc;
514  PAGED_CODE();
515 
516  /* Get ETHREAD from Handle */
517  Status = ObReferenceObjectByHandle(ThreadHandle,
519  PsThreadType,
521  (PVOID)&Thread,
522  NULL);
523  if (!NT_SUCCESS(Status)) return Status;
524 
525  /* Check if this is a System Thread */
526  if (Thread->SystemThread)
527  {
528  /* Fail */
530  goto Quit;
531  }
532 
533  /* Allocate an APC */
536  sizeof(KAPC),
537  TAG_PS_APC);
538  if (!Apc)
539  {
540  /* Fail */
542  goto Quit;
543  }
544 
545  /* Initialize the APC */
546  KeInitializeApc(Apc,
547  &Thread->Tcb,
550  NULL,
551  ApcRoutine,
552  UserMode,
553  NormalContext);
554 
555  /* Queue it */
556  if (!KeInsertQueueApc(Apc,
560  {
561  /* We failed, free it */
562  ExFreePool(Apc);
564  }
565 
566  /* Dereference Thread and Return */
567 Quit:
569  return Status;
570 }
571 
572 /*++
573  * @name NtQueueApcThread
574  * NT4
575  *
576  * This routine is used to queue an APC from user-mode for the specified
577  * thread.
578  *
579  * @param ThreadHandle
580  * Handle to the Thread.
581  * This handle must have THREAD_SET_CONTEXT privileges.
582  *
583  * @param ApcRoutine
584  * Pointer to the APC Routine to call when the APC executes.
585  *
586  * @param NormalContext
587  * Pointer to the context to send to the Normal Routine.
588  *
589  * @param SystemArgument[1-2]
590  * Pointer to a set of two parameters that contain untyped data.
591  *
592  * @return STATUS_SUCCESS or failure cute from associated calls.
593  *
594  * @remarks The thread must enter an alertable wait before the APC will be
595  * delivered.
596  *
597  *--*/
598 NTSTATUS
599 NTAPI
602  IN PVOID NormalContext,
605 {
606  return NtQueueApcThreadEx(ThreadHandle, NULL, ApcRoutine, NormalContext, SystemArgument1, SystemArgument2);
607 }
608 
609 /* EOF */
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
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:38
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:2939
#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
NTSTATUS NTAPI NtQueueApcThreadEx(IN HANDLE ThreadHandle, IN OPTIONAL HANDLE UserApcReserveHandle, IN PKNORMAL_ROUTINE ApcRoutine, IN PVOID NormalContext, IN OPTIONAL PVOID SystemArgument1, IN OPTIONAL PVOID SystemArgument2)
Definition: state.c:504
ULONG NTAPI KeResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:397
LONG NTSTATUS
Definition: precomp.h:26
EX_RUNDOWN_REF RundownProtect
Definition: pstypes.h:1090
KTHREAD Tcb
Definition: pstypes.h:1034
#define ExAcquireRundownProtection
Definition: ex.h:130
NTSTATUS NTAPI NtAlertThread(IN HANDLE ThreadHandle)
Definition: state.c:193
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:3066
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
NTSTATUS NTAPI NtSuspendThread(IN HANDLE ThreadHandle, OUT PULONG PreviousSuspendCount OPTIONAL)
Definition: state.c:352
#define PROCESS_SUSPEND_RESUME
Definition: pstypes.h:159
#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:600
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:231
#define PAGED_CODE()
Definition: video.h:57
_SEH2_TRY
Definition: create.c:4250
#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:496
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 EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
smooth NULL
Definition: ftsmooth.c:416
#define THREAD_SET_CONTEXT
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
_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 NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#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
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:535
ULONG SystemThread
Definition: pstypes.h:1113
Status
Definition: gdiplustypes.h:24
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
#define THREAD_SUSPEND_RESUME
_In_ PLARGE_INTEGER _In_opt_ PTIMER_APC_ROUTINE _In_opt_ PVOID _In_ BOOLEAN _In_opt_ LONG _Out_opt_ PBOOLEAN PreviousState
Definition: zwfuncs.h:428
NTSTATUS NTAPI PsResumeProcess(IN PEPROCESS Process)
Definition: state.c:128
_SEH2_END
Definition: create.c:4424
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
ULONG Terminated
Definition: pstypes.h:1105
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 OUT
Definition: typedefs.h:39
ULONG NTAPI KeForceResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:276
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:566
#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:632
_In_ HANDLE ProcessHandle
Definition: mmfuncs.h:403
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define STATUS_SUSPEND_COUNT_EXCEEDED
Definition: ntstatus.h:296
POBJECT_TYPE PsProcessType
Definition: process.c:20
#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
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68