diff --git a/server/object.h b/server/object.h index 56a6bcd8dc..681c807e0d 100644 --- a/server/object.h +++ b/server/object.h @@ -153,6 +153,9 @@ extern void close_registry(void); /* 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 c1a8cb785c..5667d992dd 100644 --- a/server/ptrace.c +++ b/server/ptrace.c @@ -139,23 +139,30 @@ static int wait4_thread( struct thread *thread, int signal ) { 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 @@ int send_thread_signal( struct thread *thread, int sig ) 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 @@ int suspend_for_ptrace( struct thread *thread ) 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 9ce3640016..2888015534 100644 --- a/server/signal.c +++ b/server/signal.c @@ -88,6 +88,8 @@ static struct handler *handler_sigio; static sigset_t blocked_sigset; +static int watchdog; + /* create a signal handler */ static struct handler *create_handler( signal_callback callback ) { @@ -199,6 +201,12 @@ static void do_sigint( int signum ) 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 @@ static void do_sigio( int signum, siginfo_t *si, void *x ) } #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 @@ void init_signals(void) 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 @@ void init_signals(void) 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 );