ReactOS 0.4.16-dev-336-gb667d82
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
18VOID
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
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
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 */
61 {
62 /* Guard with SEH because KeSuspendThread can raise an exception */
64 {
65 /* Do the suspend */
66 OldCount = KeSuspendThread(&Thread->Tcb);
67 }
69 {
70 /* Get the exception code */
72 }
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 */
90 {
91 /* Do the suspend */
92 OldCount = KeSuspendThread(&Thread->Tcb);
93 }
95 {
96 /* Get the exception code */
98 }
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
127NTAPI
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
157NTAPI
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 */
192NTAPI
194{
198
199 /* Reference the Object */
200 Status = ObReferenceObjectByHandle(ThreadHandle,
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
225NTAPI
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 */
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,
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 */
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
289NTAPI
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 */
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,
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 */
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
351NTAPI
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 */
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,
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 */
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
410NTAPI
412{
416 PAGED_CODE();
417
418 /* Reference the process */
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
437NTAPI
439{
443 PAGED_CODE();
444
445 /* Reference the process */
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
464NTAPI
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 *--*/
503NTAPI
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,
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,
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 */
567Quit:
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 *--*/
599NTAPI
602 IN PVOID NormalContext,
605{
606 return NtQueueApcThreadEx(ThreadHandle, NULL, ApcRoutine, NormalContext, SystemArgument1, SystemArgument2);
607}
608
609/* EOF */
#define PAGED_CODE()
LONG NTSTATUS
Definition: precomp.h:26
#define STATUS_INVALID_HANDLE
Definition: d3dkmdt.h:40
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ExReleaseRundownProtection
Definition: ex.h:136
#define ExGetPreviousMode
Definition: ex.h:140
#define ExAcquireRundownProtection
Definition: ex.h:135
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
#define PROCESS_SUSPEND_RESUME
Definition: pstypes.h:168
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define THREAD_SET_CONTEXT
#define THREAD_SUSPEND_RESUME
#define KernelMode
Definition: asm.h:34
#define UserMode
Definition: asm.h:35
_In_opt_ HANDLE _In_opt_ PIO_APC_ROUTINE ApcRoutine
Definition: iofuncs.h:726
@ OriginalApcEnvironment
Definition: ketypes.h:767
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:744
_In_ HANDLE ProcessHandle
Definition: mmfuncs.h:403
ULONG NTAPI KeForceResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:267
ULONG NTAPI KeSuspendThread(PKTHREAD Thread)
Definition: thrdobj.c:601
ULONG NTAPI KeResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:388
BOOLEAN NTAPI KeAlertThread(IN PKTHREAD Thread, IN KPROCESSOR_MODE AlertMode)
Definition: thrdobj.c:176
BOOLEAN NTAPI KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
Definition: thrdobj.c:722
ULONG NTAPI KeAlertResumeThread(IN PKTHREAD Thread)
Definition: thrdobj.c:124
BOOLEAN NTAPI KeInsertQueueApc(IN PKAPC Apc, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN KPRIORITY PriorityBoost)
Definition: apc.c:735
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
POBJECT_TYPE PsProcessType
Definition: process.c:20
NTSTATUS NTAPI PsResumeProcess(IN PEPROCESS Process)
Definition: state.c:128
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
NTSTATUS NTAPI PsSuspendThread(IN PETHREAD Thread, OUT PULONG PreviousCount OPTIONAL)
Definition: state.c:48
NTSTATUS NTAPI NtQueueApcThread(IN HANDLE ThreadHandle, IN PKNORMAL_ROUTINE ApcRoutine, IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: state.c:600
NTSTATUS NTAPI NtAlertResumeThread(IN HANDLE ThreadHandle, OUT PULONG SuspendCount)
Definition: state.c:226
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 NtAlertThread(IN HANDLE ThreadHandle)
Definition: state.c:193
NTSTATUS NTAPI NtSuspendProcess(IN HANDLE ProcessHandle)
Definition: state.c:411
NTSTATUS NTAPI PsResumeThread(IN PETHREAD Thread, OUT PULONG PreviousCount OPTIONAL)
Definition: state.c:32
NTSTATUS NTAPI PsSuspendProcess(IN PEPROCESS Process)
Definition: state.c:158
NTSTATUS NTAPI NtTestAlert(VOID)
Definition: state.c:465
NTSTATUS NTAPI NtResumeProcess(IN HANDLE ProcessHandle)
Definition: state.c:438
NTSTATUS NTAPI NtResumeThread(IN HANDLE ThreadHandle, OUT PULONG SuspendCount OPTIONAL)
Definition: state.c:290
NTSTATUS NTAPI NtSuspendThread(IN HANDLE ThreadHandle, OUT PULONG PreviousSuspendCount OPTIONAL)
Definition: state.c:352
POBJECT_TYPE PsThreadType
Definition: thread.c:20
#define STATUS_ALERTED
Definition: ntstatus.h:80
#define STATUS_THREAD_IS_TERMINATING
Definition: ntstatus.h:311
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
#define STATUS_SUSPEND_COUNT_EXCEEDED
Definition: ntstatus.h:310
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:494
PETHREAD NTAPI PsGetNextProcessThread(IN PEPROCESS Process, IN PETHREAD Thread OPTIONAL)
Definition: process.c:75
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:66
#define _SEH2_END
Definition: pseh2_64.h:155
#define _SEH2_TRY
Definition: pseh2_64.h:55
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
#define STATUS_SUCCESS
Definition: shellext.h:65
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
KTHREAD Tcb
Definition: pstypes.h:1104
EX_RUNDOWN_REF RundownProtect
Definition: pstypes.h:1160
ULONG SystemThread
Definition: pstypes.h:1183
ULONG Terminated
Definition: pstypes.h:1175
Definition: ketypes.h:547
#define TAG_PS_APC
Definition: tag.h:137
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_In_ WDF_POWER_DEVICE_STATE PreviousState
Definition: wdfdevice.h:829
#define ExAllocatePoolWithQuotaTag(a, b, c)
Definition: exfuncs.h:530
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689
#define ObDereferenceObject
Definition: obfuncs.h:203
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103