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
)
51 NTSTATUS Status
= STATUS_SUCCESS
;
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
);
67 if (ExAcquireRundownProtection(&Thread
->RundownProtect
))
69 /* Make sure the thread isn't terminating */
70 if (Thread
->Terminated
)
73 Status
= STATUS_THREAD_IS_TERMINATING
;
77 /* Otherwise, do the suspend */
78 OldCount
= KeSuspendThread(&Thread
->Tcb
);
80 /* Check if it terminated during the suspend */
81 if (Thread
->Terminated
)
83 /* Wake it back up and fail */
84 KeForceResumeThread(&Thread
->Tcb
);
85 Status
= STATUS_THREAD_IS_TERMINATING
;
90 /* Release rundown protection */
91 ExReleaseRundownProtection(&Thread
->RundownProtect
);
95 /* Thread is terminating */
96 Status
= STATUS_THREAD_IS_TERMINATING
;
100 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
102 Status
= _SEH2_GetExceptionCode();
104 /* Don't fail if we merely couldn't write the handle back */
105 if (Status
!= STATUS_SUSPEND_COUNT_EXCEEDED
) Status
= STATUS_SUCCESS
;
109 /* Write back the previous count */
110 if (PreviousCount
) *PreviousCount
= OldCount
;
116 PsResumeProcess(IN PEPROCESS Process
)
121 /* Lock the Process */
122 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
124 /* Process is terminating */
125 return STATUS_PROCESS_IS_TERMINATING
;
128 /* Get the first thread */
129 Thread
= PsGetNextProcessThread(Process
, NULL
);
133 KeResumeThread(&Thread
->Tcb
);
135 /* Move to the next thread */
136 Thread
= PsGetNextProcessThread(Process
, Thread
);
139 /* Unlock the process */
140 ExReleaseRundownProtection(&Process
->RundownProtect
);
141 return STATUS_SUCCESS
;
146 PsSuspendProcess(IN PEPROCESS Process
)
151 /* Lock the Process */
152 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
154 /* Process is terminating */
155 return STATUS_PROCESS_IS_TERMINATING
;
158 /* Get the first thread */
159 Thread
= PsGetNextProcessThread(Process
, NULL
);
163 PsSuspendThread(Thread
, NULL
);
165 /* Move to the next thread */
166 Thread
= PsGetNextProcessThread(Process
, Thread
);
169 /* Unlock the process */
170 ExReleaseRundownProtection(&Process
->RundownProtect
);
171 return STATUS_SUCCESS
;
174 /* PUBLIC FUNCTIONS **********************************************************/
181 NtAlertThread(IN HANDLE ThreadHandle
)
183 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
187 /* Reference the Object */
188 Status
= ObReferenceObjectByHandle(ThreadHandle
,
189 THREAD_SUSPEND_RESUME
,
194 if (NT_SUCCESS(Status
))
197 * Do an alert depending on the processor mode. If some kmode code wants to
198 * enforce a umode alert it should call KeAlertThread() directly. If kmode
199 * code wants to do a kmode alert it's sufficient to call it with Zw or just
200 * use KeAlertThread() directly
202 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
204 /* Dereference Object */
205 ObDereferenceObject(Thread
);
214 NtAlertResumeThread(IN HANDLE ThreadHandle
,
215 OUT PULONG SuspendCount
)
217 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
219 NTSTATUS Status
= STATUS_SUCCESS
;
222 /* Check if we came from user mode with a suspend count */
223 if ((SuspendCount
) && (PreviousMode
!= KernelMode
))
225 /* Enter SEH for probing */
228 /* Probe the count */
229 ProbeForWriteUlong(SuspendCount
);
231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
233 /* Get the exception code */
234 Status
= _SEH2_GetExceptionCode();
237 if (!NT_SUCCESS(Status
)) return Status
;
240 /* Reference the Object */
241 Status
= ObReferenceObjectByHandle(ThreadHandle
,
242 THREAD_SUSPEND_RESUME
,
247 if (NT_SUCCESS(Status
))
249 /* Call the Kernel Function */
250 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
252 /* Dereference Object */
253 ObDereferenceObject(Thread
);
255 /* Check if the caller gave a suspend count */
258 /* Enter SEH for write */
261 /* Write state back */
262 *SuspendCount
= PreviousState
;
264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
266 /* Get exception code */
267 Status
= _SEH2_GetExceptionCode();
279 NtResumeThread(IN HANDLE ThreadHandle
,
280 OUT PULONG SuspendCount OPTIONAL
)
284 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
285 NTSTATUS Status
= STATUS_SUCCESS
;
288 /* Check if caller gave a suspend count from user mode */
289 if ((SuspendCount
) && (PreviousMode
!= KernelMode
))
291 /* Enter SEH for probing */
294 /* Probe the count */
295 ProbeForWriteUlong(SuspendCount
);
297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
299 /* Get the exception code */
300 Status
= _SEH2_GetExceptionCode();
303 if(!NT_SUCCESS(Status
)) return Status
;
306 /* Get the Thread Object */
307 Status
= ObReferenceObjectByHandle(ThreadHandle
,
308 THREAD_SUSPEND_RESUME
,
313 if (!NT_SUCCESS(Status
)) return Status
;
315 /* Call the internal function */
316 Status
= PsResumeThread(Thread
, &Prev
);
318 /* Check if the caller wanted the count back */
321 /* Enter SEH for write back */
324 /* Write the count */
325 *SuspendCount
= Prev
;
327 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
329 /* Get the exception code */
330 Status
= _SEH2_GetExceptionCode();
335 /* Dereference and return */
336 ObDereferenceObject(Thread
);
342 NtSuspendThread(IN HANDLE ThreadHandle
,
343 OUT PULONG PreviousSuspendCount OPTIONAL
)
347 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
348 NTSTATUS Status
= STATUS_SUCCESS
;
351 /* Check if caller gave a suspend count from user mode */
352 if ((PreviousSuspendCount
) && (PreviousMode
!= KernelMode
))
354 /* Enter SEH for probing */
357 /* Probe the count */
358 ProbeForWriteUlong(PreviousSuspendCount
);
360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
362 /* Get the exception code */
363 Status
= _SEH2_GetExceptionCode();
366 if(!NT_SUCCESS(Status
)) return Status
;
369 /* Get the Thread Object */
370 Status
= ObReferenceObjectByHandle(ThreadHandle
,
371 THREAD_SUSPEND_RESUME
,
376 if (!NT_SUCCESS(Status
)) return Status
;
378 /* Call the internal function */
379 Status
= PsSuspendThread(Thread
, &Prev
);
380 ObDereferenceObject(Thread
);
381 if (!NT_SUCCESS(Status
)) return Status
;
383 /* Protect write with SEH */
386 /* Return the Previous Count */
387 if (PreviousSuspendCount
) *PreviousSuspendCount
= Prev
;
389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
391 /* Get the exception code */
392 Status
= _SEH2_GetExceptionCode();
402 NtSuspendProcess(IN HANDLE ProcessHandle
)
404 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
409 /* Reference the process */
410 Status
= ObReferenceObjectByHandle(ProcessHandle
,
411 PROCESS_SUSPEND_RESUME
,
416 if (NT_SUCCESS(Status
))
418 /* Call the internal function */
419 Status
= PsSuspendProcess(Process
);
420 ObDereferenceObject(Process
);
429 NtResumeProcess(IN HANDLE ProcessHandle
)
431 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
436 /* Reference the process */
437 Status
= ObReferenceObjectByHandle(ProcessHandle
,
438 PROCESS_SUSPEND_RESUME
,
443 if (NT_SUCCESS(Status
))
445 /* Call the internal function */
446 Status
= PsResumeProcess(Process
);
447 ObDereferenceObject(Process
);
458 /* Check and Alert Thread if needed */
459 return KeTestAlertThread(ExGetPreviousMode()) ?
460 STATUS_ALERTED
: STATUS_SUCCESS
;
464 * @name NtQueueApcThread
467 * This routine is used to queue an APC from user-mode for the specified
470 * @param ThreadHandle
471 * Handle to the Thread.
472 * This handle must have THREAD_SET_CONTEXT privileges.
475 * Pointer to the APC Routine to call when the APC executes.
477 * @param NormalContext
478 * Pointer to the context to send to the Normal Routine.
480 * @param SystemArgument[1-2]
481 * Pointer to a set of two parameters that contain untyped data.
483 * @return STATUS_SUCCESS or failure cute from associated calls.
485 * @remarks The thread must enter an alertable wait before the APC will be
491 NtQueueApcThread(IN HANDLE ThreadHandle
,
492 IN PKNORMAL_ROUTINE ApcRoutine
,
493 IN PVOID NormalContext
,
494 IN PVOID SystemArgument1
,
495 IN PVOID SystemArgument2
)
499 NTSTATUS Status
= STATUS_SUCCESS
;
502 /* Get ETHREAD from Handle */
503 Status
= ObReferenceObjectByHandle(ThreadHandle
,
509 if (NT_SUCCESS(Status
)) return Status
;
511 /* Check if this is a System Thread */
512 if (Thread
->SystemThread
)
515 Status
= STATUS_INVALID_HANDLE
;
519 /* Allocate an APC */
520 Apc
= ExAllocatePoolWithTag(NonPagedPool
|
521 POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
527 Status
= STATUS_NO_MEMORY
;
531 /* Initialize the APC */
534 OriginalApcEnvironment
,
535 PspQueueApcSpecialApc
,
542 if (!KeInsertQueueApc(Apc
,
547 /* We failed, free it */
549 Status
= STATUS_UNSUCCESSFUL
;
552 /* Dereference Thread and Return */
554 ObDereferenceObject(Thread
);