Added a watchdog mechanism to break out of the wait4 call in case it
didn't return properly (can happen at thread exit).

diff --git a/server/object.h b/server/object.h
index 56a6bcd..681c807 100644
--- a/server/object.h
+++ b/server/object.h
@@ -153,6 +153,9 @@
 
 /* signal functions */
 
+extern void start_watchdog(void);
+extern void stop_watchdog(void);
+extern int watchdog_triggered(void);
 extern void init_signals(void);
 extern void close_signals(void);
 
diff --git a/server/ptrace.c b/server/ptrace.c
index c1a8cb7..5667d99 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -139,23 +139,30 @@
 {
     int res, status;
 
+    start_watchdog();
     for (;;)
     {
         if ((res = wait4_wrapper( get_ptrace_pid(thread), &status, WUNTRACED, NULL )) == -1)
         {
-            if (errno == EINTR) continue;
-            if (errno == ECHILD)  /* must have died */
+            if (errno == EINTR)
+            {
+                if (!watchdog_triggered()) continue;
+                if (debug_level) fprintf( stderr, "%04x: *watchdog* wait4 aborted\n", thread->id );
+            }
+            else if (errno == ECHILD)  /* must have died */
             {
                 thread->unix_pid = -1;
                 thread->unix_tid = -1;
                 thread->attached = 0;
             }
             else perror( "wait4" );
+            stop_watchdog();
             return 0;
         }
         res = handle_child_status( thread, res, status, signal );
         if (!res || res == signal) break;
     }
+    stop_watchdog();
     return (thread->unix_pid != -1);
 }
 
@@ -190,21 +197,6 @@
     return (ret != -1);
 }
 
-/* attach to a Unix thread */
-static int attach_thread( struct thread *thread )
-{
-    /* this may fail if the client is already being debugged */
-    if (!use_ptrace) return 0;
-    if (ptrace( PTRACE_ATTACH, get_ptrace_pid(thread), 0, 0 ) == -1)
-    {
-        if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1;  /* thread got killed */
-        return 0;
-    }
-    if (debug_level) fprintf( stderr, "%04x: *attached*\n", thread->id );
-    thread->attached = 1;
-    return wait4_thread( thread, SIGSTOP );
-}
-
 /* detach from a Unix thread and kill it */
 void detach_thread( struct thread *thread, int sig )
 {
@@ -264,10 +256,21 @@
     if (thread->attached)
     {
         if (!send_thread_signal( thread, SIGSTOP )) goto error;
-        if (!wait4_thread( thread, SIGSTOP )) goto error;
-        return 1;
     }
-    if (attach_thread( thread )) return 1;
+    else
+    {
+        /* this may fail if the client is already being debugged */
+        if (!use_ptrace) goto error;
+        if (ptrace( PTRACE_ATTACH, get_ptrace_pid(thread), 0, 0 ) == -1)
+        {
+            if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1;  /* thread got killed */
+            goto error;
+        }
+        if (debug_level) fprintf( stderr, "%04x: *attached*\n", thread->id );
+        thread->attached = 1;
+    }
+    if (wait4_thread( thread, SIGSTOP )) return 1;
+    resume_after_ptrace( thread );
  error:
     set_error( STATUS_ACCESS_DENIED );
     return 0;
diff --git a/server/signal.c b/server/signal.c
index 9ce3640..2888015 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -88,6 +88,8 @@
 
 static sigset_t blocked_sigset;
 
+static int watchdog;
+
 /* create a signal handler */
 static struct handler *create_handler( signal_callback callback )
 {
@@ -199,6 +201,12 @@
     do_signal( handler_sigint );
 }
 
+/* SIGALRM handler */
+static void do_sigalrm( int signum )
+{
+    watchdog = 1;
+}
+
 /* SIGCHLD handler */
 static void do_sigchld( int signum )
 {
@@ -214,6 +222,23 @@
 }
 #endif
 
+void start_watchdog(void)
+{
+    alarm( 3 );
+    watchdog = 0;
+}
+
+void stop_watchdog(void)
+{
+    alarm( 0 );
+    watchdog = 0;
+}
+
+int watchdog_triggered(void)
+{
+    return watchdog != 0;
+}
+
 void init_signals(void)
 {
     struct sigaction action;
@@ -228,6 +253,7 @@
     sigaddset( &blocked_sigset, SIGCHLD );
     sigaddset( &blocked_sigset, SIGHUP );
     sigaddset( &blocked_sigset, SIGINT );
+    sigaddset( &blocked_sigset, SIGALRM );
     sigaddset( &blocked_sigset, SIGIO );
     sigaddset( &blocked_sigset, SIGQUIT );
     sigaddset( &blocked_sigset, SIGTERM );
@@ -246,6 +272,8 @@
     sigaction( SIGHUP, &action, NULL );
     action.sa_handler = do_sigint;
     sigaction( SIGINT, &action, NULL );
+    action.sa_handler = do_sigalrm;
+    sigaction( SIGALRM, &action, NULL );
     action.sa_handler = do_sigterm;
     sigaction( SIGQUIT, &action, NULL );
     sigaction( SIGTERM, &action, NULL );