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
;
50 OUT PULONG PreviousCount OPTIONAL
)
57 Status
= STATUS_SUCCESS
;
59 /* Check if we're suspending ourselves */
60 if (Thread
== PsGetCurrentThread())
62 /* Guard with SEH because KeSuspendThread can raise an exception */
66 OldCount
= KeSuspendThread(&Thread
->Tcb
);
68 _SEH2_EXCEPT(_SEH2_GetExceptionCode() == STATUS_SUSPEND_COUNT_EXCEEDED
)
70 /* Get the exception code */
71 Status
= _SEH2_GetExceptionCode();
77 /* Acquire rundown protection */
78 if (ExAcquireRundownProtection(&Thread
->RundownProtect
))
80 /* Make sure the thread isn't terminating */
81 if (Thread
->Terminated
)
84 Status
= STATUS_THREAD_IS_TERMINATING
;
88 /* Guard with SEH because KeSuspendThread can raise an exception */
92 OldCount
= KeSuspendThread(&Thread
->Tcb
);
94 _SEH2_EXCEPT(_SEH2_GetExceptionCode() == STATUS_SUSPEND_COUNT_EXCEEDED
)
96 /* Get the exception code */
97 Status
= _SEH2_GetExceptionCode();
101 /* Check if it was terminated during the suspend */
102 if (Thread
->Terminated
)
104 /* Wake it back up and fail */
105 KeForceResumeThread(&Thread
->Tcb
);
106 Status
= STATUS_THREAD_IS_TERMINATING
;
111 /* Release rundown protection */
112 ExReleaseRundownProtection(&Thread
->RundownProtect
);
116 /* Thread is terminating */
117 Status
= STATUS_THREAD_IS_TERMINATING
;
121 /* Write back the previous count */
122 if (PreviousCount
) *PreviousCount
= OldCount
;
128 PsResumeProcess(IN PEPROCESS Process
)
133 /* Lock the Process */
134 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
136 /* Process is terminating */
137 return STATUS_PROCESS_IS_TERMINATING
;
140 /* Get the first thread */
141 Thread
= PsGetNextProcessThread(Process
, NULL
);
145 KeResumeThread(&Thread
->Tcb
);
147 /* Move to the next thread */
148 Thread
= PsGetNextProcessThread(Process
, Thread
);
151 /* Unlock the process */
152 ExReleaseRundownProtection(&Process
->RundownProtect
);
153 return STATUS_SUCCESS
;
158 PsSuspendProcess(IN PEPROCESS Process
)
163 /* Lock the Process */
164 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
166 /* Process is terminating */
167 return STATUS_PROCESS_IS_TERMINATING
;
170 /* Get the first thread */
171 Thread
= PsGetNextProcessThread(Process
, NULL
);
175 PsSuspendThread(Thread
, NULL
);
177 /* Move to the next thread */
178 Thread
= PsGetNextProcessThread(Process
, Thread
);
181 /* Unlock the process */
182 ExReleaseRundownProtection(&Process
->RundownProtect
);
183 return STATUS_SUCCESS
;
186 /* PUBLIC FUNCTIONS **********************************************************/
193 NtAlertThread(IN HANDLE ThreadHandle
)
195 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
199 /* Reference the Object */
200 Status
= ObReferenceObjectByHandle(ThreadHandle
,
201 THREAD_SUSPEND_RESUME
,
206 if (NT_SUCCESS(Status
))
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
214 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
216 /* Dereference Object */
217 ObDereferenceObject(Thread
);
226 NtAlertResumeThread(IN HANDLE ThreadHandle
,
227 OUT PULONG SuspendCount
)
229 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
234 /* Check if we came from user mode with a suspend count */
235 if ((SuspendCount
) && (PreviousMode
!= KernelMode
))
237 /* Enter SEH for probing */
240 /* Probe the count */
241 ProbeForWriteUlong(SuspendCount
);
243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
245 /* Return the exception code */
246 _SEH2_YIELD(return _SEH2_GetExceptionCode());
251 /* Reference the Object */
252 Status
= ObReferenceObjectByHandle(ThreadHandle
,
253 THREAD_SUSPEND_RESUME
,
258 if (NT_SUCCESS(Status
))
260 /* Call the Kernel Function */
261 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
263 /* Dereference Object */
264 ObDereferenceObject(Thread
);
266 /* Check if the caller gave a suspend count */
269 /* Enter SEH for write */
272 /* Write state back */
273 *SuspendCount
= PreviousState
;
275 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
277 /* Get exception code */
278 Status
= _SEH2_GetExceptionCode();
290 NtResumeThread(IN HANDLE ThreadHandle
,
291 OUT PULONG SuspendCount OPTIONAL
)
295 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
299 /* Check if caller gave a suspend count from user mode */
300 if ((SuspendCount
) && (PreviousMode
!= KernelMode
))
302 /* Enter SEH for probing */
305 /* Probe the count */
306 ProbeForWriteUlong(SuspendCount
);
308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
310 /* Return the exception code */
311 _SEH2_YIELD(return _SEH2_GetExceptionCode());
316 /* Get the Thread Object */
317 Status
= ObReferenceObjectByHandle(ThreadHandle
,
318 THREAD_SUSPEND_RESUME
,
323 if (!NT_SUCCESS(Status
)) return Status
;
325 /* Call the internal function */
326 Status
= PsResumeThread(Thread
, &Prev
);
328 /* Check if the caller wanted the count back */
331 /* Enter SEH for write back */
334 /* Write the count */
335 *SuspendCount
= Prev
;
337 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
339 /* Get the exception code */
340 Status
= _SEH2_GetExceptionCode();
345 /* Dereference and return */
346 ObDereferenceObject(Thread
);
352 NtSuspendThread(IN HANDLE ThreadHandle
,
353 OUT PULONG PreviousSuspendCount OPTIONAL
)
357 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
361 /* Check if caller gave a suspend count from user mode */
362 if ((PreviousSuspendCount
) && (PreviousMode
!= KernelMode
))
364 /* Enter SEH for probing */
367 /* Probe the count */
368 ProbeForWriteUlong(PreviousSuspendCount
);
370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
372 /* Return the exception code */
373 _SEH2_YIELD(return _SEH2_GetExceptionCode());
378 /* Get the Thread Object */
379 Status
= ObReferenceObjectByHandle(ThreadHandle
,
380 THREAD_SUSPEND_RESUME
,
385 if (!NT_SUCCESS(Status
)) return Status
;
387 /* Call the internal function */
388 Status
= PsSuspendThread(Thread
, &Prev
);
389 ObDereferenceObject(Thread
);
390 if (!NT_SUCCESS(Status
)) return Status
;
392 /* Protect write with SEH */
395 /* Return the Previous Count */
396 if (PreviousSuspendCount
) *PreviousSuspendCount
= Prev
;
398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
400 /* Get the exception code */
401 Status
= _SEH2_GetExceptionCode();
411 NtSuspendProcess(IN HANDLE ProcessHandle
)
413 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
418 /* Reference the process */
419 Status
= ObReferenceObjectByHandle(ProcessHandle
,
420 PROCESS_SUSPEND_RESUME
,
425 if (NT_SUCCESS(Status
))
427 /* Call the internal function */
428 Status
= PsSuspendProcess(Process
);
429 ObDereferenceObject(Process
);
438 NtResumeProcess(IN HANDLE ProcessHandle
)
440 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
445 /* Reference the process */
446 Status
= ObReferenceObjectByHandle(ProcessHandle
,
447 PROCESS_SUSPEND_RESUME
,
452 if (NT_SUCCESS(Status
))
454 /* Call the internal function */
455 Status
= PsResumeProcess(Process
);
456 ObDereferenceObject(Process
);
467 /* Check and Alert Thread if needed */
468 return KeTestAlertThread(ExGetPreviousMode()) ?
469 STATUS_ALERTED
: STATUS_SUCCESS
;
473 * @name NtQueueApcThread
476 * This routine is used to queue an APC from user-mode for the specified
479 * @param ThreadHandle
480 * Handle to the Thread.
481 * This handle must have THREAD_SET_CONTEXT privileges.
484 * Pointer to the APC Routine to call when the APC executes.
486 * @param NormalContext
487 * Pointer to the context to send to the Normal Routine.
489 * @param SystemArgument[1-2]
490 * Pointer to a set of two parameters that contain untyped data.
492 * @return STATUS_SUCCESS or failure cute from associated calls.
494 * @remarks The thread must enter an alertable wait before the APC will be
500 NtQueueApcThread(IN HANDLE ThreadHandle
,
501 IN PKNORMAL_ROUTINE ApcRoutine
,
502 IN PVOID NormalContext
,
503 IN PVOID SystemArgument1
,
504 IN PVOID SystemArgument2
)
508 NTSTATUS Status
= STATUS_SUCCESS
;
511 /* Get ETHREAD from Handle */
512 Status
= ObReferenceObjectByHandle(ThreadHandle
,
518 if (!NT_SUCCESS(Status
)) return Status
;
520 /* Check if this is a System Thread */
521 if (Thread
->SystemThread
)
524 Status
= STATUS_INVALID_HANDLE
;
528 /* Allocate an APC */
529 Apc
= ExAllocatePoolWithTag(NonPagedPool
|
530 POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
536 Status
= STATUS_NO_MEMORY
;
540 /* Initialize the APC */
543 OriginalApcEnvironment
,
544 PspQueueApcSpecialApc
,
551 if (!KeInsertQueueApc(Apc
,
556 /* We failed, free it */
558 Status
= STATUS_UNSUCCESSFUL
;
561 /* Dereference Thread and Return */
563 ObDereferenceObject(Thread
);