- Fix NtSuspendThread: correct PreviousMode check, return error if thread is terminat...
[reactos.git] / reactos / ntoskrnl / ps / suspend.c
index 3b50812..98e3a90 100644 (file)
@@ -115,25 +115,22 @@ NtSuspendThread(IN HANDLE ThreadHandle,
 {
     PETHREAD Thread;
     ULONG Prev;
-    KPROCESSOR_MODE PreviousMode;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status = STATUS_SUCCESS;
-
     PAGED_CODE();
 
-    PreviousMode = ExGetPreviousMode();
-
     /* Check buffer validity */
-    if(PreviousSuspendCount && PreviousMode == UserMode) {
-
-        _SEH_TRY {
-
+    if(PreviousSuspendCount && PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
             ProbeForWrite(PreviousSuspendCount,
                           sizeof(ULONG),
                           sizeof(ULONG));
-         } _SEH_HANDLE {
-
+         }
+        _SEH_HANDLE
+        {
             Status = _SEH_GetExceptionCode();
-
         } _SEH_END;
 
         if(!NT_SUCCESS(Status)) return Status;
@@ -146,30 +143,34 @@ NtSuspendThread(IN HANDLE ThreadHandle,
                                        PreviousMode,
                                        (PVOID*)&Thread,
                                        NULL);
-    if (!NT_SUCCESS(Status)) {
+    if (!NT_SUCCESS(Status)) return Status;
 
-        return Status;
+    /* Guard with SEH because KeSuspendThread can raise an exception */
+    _SEH_TRY
+    {
+        /* Make sure the thread isn't terminating */
+        if ((Thread != PsGetCurrentThread()) && (Thread->Terminated))
+        {
+            ObDereferenceObject(Thread);
+            return STATUS_THREAD_IS_TERMINATING;
+        }
+
+        /* Call the Kernel function */
+        Prev = KeSuspendThread(&Thread->Tcb);
+
+        /* Return the Previous Count */
+        if (PreviousSuspendCount) *PreviousSuspendCount = Prev;
     }
+    _SEH_HANDLE
+    {
+        Status = _SEH_GetExceptionCode();
 
-    /* Call the Kernel Function */
-    Prev = KeSuspendThread(&Thread->Tcb);
-
-    /* Return it */
-    if(PreviousSuspendCount) {
-
-        _SEH_TRY {
-
-            *PreviousSuspendCount = Prev;
-
-        } _SEH_HANDLE {
-
-            Status = _SEH_GetExceptionCode();
+        /* Don't fail if we merely couldn't write the handle back */
+        if (Status != STATUS_SUSPEND_COUNT_EXCEEDED) Status = STATUS_SUCCESS;
+    } _SEH_END;
 
-        } _SEH_END;
-    }
-
-    /* Dereference and Return */
-    ObDereferenceObject((PVOID)Thread);
+    /* Return */
+    ObDereferenceObject(Thread);
     return Status;
 }