Avoid SIGSTOP/SIGCONT race when ptrace is disabled.

diff --git a/server/process.c b/server/process.c
index 297ef00..8073e55 100644
--- a/server/process.c
+++ b/server/process.c
@@ -462,8 +462,7 @@
         set_error( STATUS_ACCESS_DENIED );
         return;
     }
-    suspend_thread( thread, 0 );
-    if (thread->attached)
+    if (suspend_for_ptrace( thread ))
     {
         while (len > 0 && max)
         {
@@ -483,10 +482,9 @@
             }
             if (len && (read_thread_int( thread, addr + len - 1, &dummy ) == -1)) goto done;
         }
+    done:
+        resume_thread( thread );
     }
-    else set_error( STATUS_ACCESS_DENIED );
- done:
-    resume_thread( thread );
 }
 
 /* write data to a process memory space */
@@ -508,8 +506,7 @@
         set_error( STATUS_ACCESS_DENIED );
         return;
     }
-    suspend_thread( thread, 0 );
-    if (thread->attached)
+    if (suspend_for_ptrace( thread ))
     {
         /* first word is special */
         if (len > 1)
@@ -544,10 +541,9 @@
             }
             if (len && (write_thread_int( thread, addr + len - 1, 0, 0 ) == -1)) goto done;
         }
+    done:
+        resume_thread( thread );
     }
-    else set_error( STATUS_ACCESS_DENIED );
- done:
-    resume_thread( thread );
 }
 
 /* take a snapshot of currently running processes */
diff --git a/server/ptrace.c b/server/ptrace.c
index 58339f6..9cd4c04 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -157,6 +157,25 @@
     else ptrace( PTRACE_CONT, thread->unix_pid, 1, SIGSTOP );
 }
 
+/* suspend a thread to allow using ptrace on it */
+/* you must do a resume_thread when finished with the thread */
+int suspend_for_ptrace( struct thread *thread )
+{
+    if (thread->attached)
+    {
+        suspend_thread( thread, 0 );
+        return 1;
+    }
+    if (attach_thread( thread ))
+    {
+        /* the attach will have suspended it */
+        thread->suspend++;
+        return 1;
+    }
+    set_error( STATUS_ACCESS_DENIED );
+    return 0;
+}
+
 /* read an int from a thread address space */
 int read_thread_int( struct thread *thread, const int *addr, int *data )
 {
diff --git a/server/thread.c b/server/thread.c
index 37db99b..e82c4a7 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -541,8 +541,7 @@
         set_error( STATUS_INVALID_PARAMETER );  /* FIXME */
         return;
     }
-    suspend_thread( thread, 0 );
-    if (thread->attached)
+    if (suspend_for_ptrace( thread ))
     {
         unsigned char flags_buf[4];
         int *addr = (int *)thread->process->ldt_copy + 2 * entry;
@@ -551,10 +550,9 @@
         addr = (int *)thread->process->ldt_flags + (entry >> 2);
         if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done;
         *flags = flags_buf[entry & 3];
+    done:
+        resume_thread( thread );
     }
-    else set_error( STATUS_ACCESS_DENIED );
- done:
-    resume_thread( thread );
 }
 
 /* kill a thread on the spot */
diff --git a/server/thread.h b/server/thread.h
index 198b77d..71baa51 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -86,6 +86,7 @@
 extern void stop_thread( struct thread *thread );
 extern void continue_thread( struct thread *thread );
 extern void detach_thread( struct thread *thread );
+extern int suspend_for_ptrace( struct thread *thread );
 extern int read_thread_int( struct thread *thread, const int *addr, int *data );
 extern int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask );