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)
10 /* INCLUDES ******************************************************************/
16 /* PRIVATE FUNCTIONS *********************************************************/
20 PspQueueApcSpecialApc(IN PKAPC Apc
,
21 IN OUT PKNORMAL_ROUTINE
* NormalRoutine
,
22 IN OUT PVOID
* NormalContext
,
23 IN OUT PVOID
* SystemArgument1
,
24 IN OUT PVOID
* SystemArgument2
)
26 /* Free the APC and do nothing else */
32 PsResumeThread(IN PETHREAD Thread
,
33 OUT PULONG PreviousCount OPTIONAL
)
38 /* Resume the thread */
39 OldCount
= KeResumeThread(&Thread
->Tcb
);
41 /* Return the count if asked */
42 if (PreviousCount
) *PreviousCount
= OldCount
;
43 return STATUS_SUCCESS
;
48 PsSuspendThread(IN PETHREAD Thread
,
49 OUT PULONG PreviousCount OPTIONAL
)
55 /* Guard with SEH because KeSuspendThread can raise an exception */
58 /* Check if we're suspending ourselves */
59 if (Thread
== PsGetCurrentThread())
62 OldCount
= KeSuspendThread(&Thread
->Tcb
);
65 Status
= STATUS_SUCCESS
;
70 if (ExAcquireRundownProtection(&Thread
->RundownProtect
))
72 /* Make sure the thread isn't terminating */
73 if (Thread
->Terminated
)
76 Status
= STATUS_THREAD_IS_TERMINATING
;
80 /* Otherwise, do the suspend */
81 OldCount
= KeSuspendThread(&Thread
->Tcb
);
83 /* Check if it terminated during the suspend */
84 if (Thread
->Terminated
)
86 /* Wake it back up and fail */
87 KeForceResumeThread(&Thread
->Tcb
);
88 Status
= STATUS_THREAD_IS_TERMINATING
;
93 /* Release rundown protection */
94 ExReleaseRundownProtection(&Thread
->RundownProtect
);
97 Status
= STATUS_SUCCESS
;
101 /* Thread is terminating */
102 Status
= STATUS_THREAD_IS_TERMINATING
;
106 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
108 /* Get the exception code */
109 Status
= _SEH2_GetExceptionCode();
111 /* Don't fail if we merely couldn't write the handle back */
112 if (Status
!= STATUS_SUSPEND_COUNT_EXCEEDED
) Status
= STATUS_SUCCESS
;
116 /* Write back the previous count */
117 if (PreviousCount
) *PreviousCount
= OldCount
;
123 PsResumeProcess(IN PEPROCESS Process
)
128 /* Lock the Process */
129 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
131 /* Process is terminating */
132 return STATUS_PROCESS_IS_TERMINATING
;
135 /* Get the first thread */
136 Thread
= PsGetNextProcessThread(Process
, NULL
);
140 KeResumeThread(&Thread
->Tcb
);
142 /* Move to the next thread */
143 Thread
= PsGetNextProcessThread(Process
, Thread
);
146 /* Unlock the process */
147 ExReleaseRundownProtection(&Process
->RundownProtect
);
148 return STATUS_SUCCESS
;
153 PsSuspendProcess(IN PEPROCESS Process
)
158 /* Lock the Process */
159 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
161 /* Process is terminating */
162 return STATUS_PROCESS_IS_TERMINATING
;
165 /* Get the first thread */
166 Thread
= PsGetNextProcessThread(Process
, NULL
);
170 PsSuspendThread(Thread
, NULL
);
172 /* Move to the next thread */
173 Thread
= PsGetNextProcessThread(Process
, Thread
);
176 /* Unlock the process */
177 ExReleaseRundownProtection(&Process
->RundownProtect
);
178 return STATUS_SUCCESS
;
181 /* PUBLIC FUNCTIONS **********************************************************/
188 NtAlertThread(IN HANDLE ThreadHandle
)
190 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
194 /* Reference the Object */
195 Status
= ObReferenceObjectByHandle(ThreadHandle
,
196 THREAD_SUSPEND_RESUME
,
201 if (NT_SUCCESS(Status
))
204 * Do an alert depending on the processor mode. If some kmode code wants to
205 * enforce a umode alert it should call KeAlertThread() directly. If kmode
206 * code wants to do a kmode alert it's sufficient to call it with Zw or just
207 * use KeAlertThread() directly
209 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
211 /* Dereference Object */
212 ObDereferenceObject(Thread
);
221 NtAlertResumeThread(IN HANDLE ThreadHandle
,
222 OUT PULONG SuspendCount
)
224 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
229 /* Check if we came from user mode with a suspend count */
230 if ((SuspendCount
) && (PreviousMode
!= KernelMode
))
232 /* Enter SEH for probing */
235 /* Probe the count */
236 ProbeForWriteUlong(SuspendCount
);
238 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
240 /* Return the exception code */
241 _SEH2_YIELD(return _SEH2_GetExceptionCode());
246 /* Reference the Object */
247 Status
= ObReferenceObjectByHandle(ThreadHandle
,
248 THREAD_SUSPEND_RESUME
,
253 if (NT_SUCCESS(Status
))
255 /* Call the Kernel Function */
256 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
258 /* Dereference Object */
259 ObDereferenceObject(Thread
);
261 /* Check if the caller gave a suspend count */
264 /* Enter SEH for write */
267 /* Write state back */
268 *SuspendCount
= PreviousState
;
270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
272 /* Get exception code */
273 Status
= _SEH2_GetExceptionCode();
285 NtResumeThread(IN HANDLE ThreadHandle
,
286 OUT PULONG SuspendCount OPTIONAL
)
290 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
294 /* Check if caller gave a suspend count from user mode */
295 if ((SuspendCount
) && (PreviousMode
!= KernelMode
))
297 /* Enter SEH for probing */
300 /* Probe the count */
301 ProbeForWriteUlong(SuspendCount
);
303 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
305 /* Return the exception code */
306 _SEH2_YIELD(return _SEH2_GetExceptionCode());
311 /* Get the Thread Object */
312 Status
= ObReferenceObjectByHandle(ThreadHandle
,
313 THREAD_SUSPEND_RESUME
,
318 if (!NT_SUCCESS(Status
)) return Status
;
320 /* Call the internal function */
321 Status
= PsResumeThread(Thread
, &Prev
);
323 /* Check if the caller wanted the count back */
326 /* Enter SEH for write back */
329 /* Write the count */
330 *SuspendCount
= Prev
;
332 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
334 /* Get the exception code */
335 Status
= _SEH2_GetExceptionCode();
340 /* Dereference and return */
341 ObDereferenceObject(Thread
);
347 NtSuspendThread(IN HANDLE ThreadHandle
,
348 OUT PULONG PreviousSuspendCount OPTIONAL
)
352 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
356 /* Check if caller gave a suspend count from user mode */
357 if ((PreviousSuspendCount
) && (PreviousMode
!= KernelMode
))
359 /* Enter SEH for probing */
362 /* Probe the count */
363 ProbeForWriteUlong(PreviousSuspendCount
);
365 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
367 /* Return the exception code */
368 _SEH2_YIELD(return _SEH2_GetExceptionCode());
373 /* Get the Thread Object */
374 Status
= ObReferenceObjectByHandle(ThreadHandle
,
375 THREAD_SUSPEND_RESUME
,
380 if (!NT_SUCCESS(Status
)) return Status
;
382 /* Call the internal function */
383 Status
= PsSuspendThread(Thread
, &Prev
);
384 ObDereferenceObject(Thread
);
385 if (!NT_SUCCESS(Status
)) return Status
;
387 /* Protect write with SEH */
390 /* Return the Previous Count */
391 if (PreviousSuspendCount
) *PreviousSuspendCount
= Prev
;
393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
395 /* Get the exception code */
396 Status
= _SEH2_GetExceptionCode();
406 NtSuspendProcess(IN HANDLE ProcessHandle
)
408 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
413 /* Reference the process */
414 Status
= ObReferenceObjectByHandle(ProcessHandle
,
415 PROCESS_SUSPEND_RESUME
,
420 if (NT_SUCCESS(Status
))
422 /* Call the internal function */
423 Status
= PsSuspendProcess(Process
);
424 ObDereferenceObject(Process
);
433 NtResumeProcess(IN HANDLE ProcessHandle
)
435 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
440 /* Reference the process */
441 Status
= ObReferenceObjectByHandle(ProcessHandle
,
442 PROCESS_SUSPEND_RESUME
,
447 if (NT_SUCCESS(Status
))
449 /* Call the internal function */
450 Status
= PsResumeProcess(Process
);
451 ObDereferenceObject(Process
);
462 /* Check and Alert Thread if needed */
463 return KeTestAlertThread(ExGetPreviousMode()) ?
464 STATUS_ALERTED
: STATUS_SUCCESS
;
468 * @name NtQueueApcThread
471 * This routine is used to queue an APC from user-mode for the specified
474 * @param ThreadHandle
475 * Handle to the Thread.
476 * This handle must have THREAD_SET_CONTEXT privileges.
479 * Pointer to the APC Routine to call when the APC executes.
481 * @param NormalContext
482 * Pointer to the context to send to the Normal Routine.
484 * @param SystemArgument[1-2]
485 * Pointer to a set of two parameters that contain untyped data.
487 * @return STATUS_SUCCESS or failure cute from associated calls.
489 * @remarks The thread must enter an alertable wait before the APC will be
495 NtQueueApcThread(IN HANDLE ThreadHandle
,
496 IN PKNORMAL_ROUTINE ApcRoutine
,
497 IN PVOID NormalContext
,
498 IN PVOID SystemArgument1
,
499 IN PVOID SystemArgument2
)
503 NTSTATUS Status
= STATUS_SUCCESS
;
506 /* Get ETHREAD from Handle */
507 Status
= ObReferenceObjectByHandle(ThreadHandle
,
513 if (!NT_SUCCESS(Status
)) return Status
;
515 /* Check if this is a System Thread */
516 if (Thread
->SystemThread
)
519 Status
= STATUS_INVALID_HANDLE
;
523 /* Allocate an APC */
524 Apc
= ExAllocatePoolWithTag(NonPagedPool
|
525 POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
531 Status
= STATUS_NO_MEMORY
;
535 /* Initialize the APC */
538 OriginalApcEnvironment
,
539 PspQueueApcSpecialApc
,
546 if (!KeInsertQueueApc(Apc
,
551 /* We failed, free it */
553 Status
= STATUS_UNSUCCESSFUL
;
556 /* Dereference Thread and Return */
558 ObDereferenceObject(Thread
);