From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9978 invoked by alias); 16 Oct 2008 02:54:57 -0000 Received: (qmail 9970 invoked by uid 22791); 16 Oct 2008 02:54:54 -0000 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 16 Oct 2008 02:54:16 +0000 Received: (qmail 29665 invoked from network); 16 Oct 2008 02:54:13 -0000 Received: from unknown (HELO ?192.168.0.104?) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 16 Oct 2008 02:54:13 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: RFA: non-stop/linux, thread stopping Date: Thu, 16 Oct 2008 02:54:00 -0000 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_vzq9ICEnJ/xHMte" Message-Id: <200810160354.39189.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-10/txt/msg00391.txt.bz2 --Boundary-00=_vzq9ICEnJ/xHMte Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Content-length: 3634 Hi all, [ Yet another patch preparing for remote non-stop. ] While designing the remote non-stop protocol, and the "interrupt", "interrupt -a" support, we came up with a new vCont extension, `vCont;t', or applied to a thread, `vCont;t:TID', meaning, roughly: "stop/suspend the target thread TID, however you can and feel like. If nothing interesting happens to the thread while stopping it, then report back a TARGET_SIGNAL_0, because I don't care how the thread was suspended behind the scenes. You take care of it." This takes advantage of the fact that TARGET_SIGNAL_0 is defined as: src/include/gdb/signal.h: /* Used some places (e.g. stop_signal) to record the concept that there is no signal. */ TARGET_SIGNAL_0 = 0, When implementing this on gdbserver (ptrace/linux), this effectivelly translated into stopping an LWP with SIGSTOP, nicelly moving away from SIGINT, process groups, shared or not-shared signal queues and the like. Another propertly of `vCont;t', is that it is defined as doing nothing to already stopped threads. This requirement (to not do anything to stopped threads), implies that threads that were already stopped due to internal events when an explicit stop is requested, most notably, threads that are stopped waiting for their turn in the displaced stepping queue (*), should remain stopped, and GDB should report that stop as if the target had done so itself. That is, GDB should make the stop "public". There are cases where this property is useful, and following patches will rely on it. *) remember we only have one scratch space currently, so we can only ool-step one thread at a time. This patch changes native linux non-stop to behave the same, and adds the necessary glue to the common code. To make it nicer on the eye, I'm making an output change in the CLI: New: [Thread 0xf7e306b0 (LWP 26335)] #1 stopped. 0xffffe410 in __kernel_vsyscall () Old: Program received signal 0, Signal 0. 0xffffe410 in __kernel_vsyscall () The old output is IMHO, very weird, as a program usually doesn't stop with a signal 0. :-) It also lacked information of which thread had stopped. No MI changes are necessary. *stopped,reason="signal-received",signal-name="0" is still OK. A frontend can then react accordingly to how the thread was stopped, and treat signal 0 specialy if it wants to: Say, if it was a TARGET_SIGNAL_0, then just perhaps update the thread state icon in a thread tree view, by displaying a "pause" icon. If it is was a SIGINT, SIGSEGV or some other signal, then popup a message box, for example. How does this all sound? I'm certain that handle_inferior_event will need a bit more tweaking here and there to acommodate corner cases, but I don't expect much. The base principle is "if the thread had an explicit request to stop, then when we get a stop event, don't resume it automatically.". That's all. About the code changes themselves: - I'm using an observer to make two GDB components comunicate. thread.c -> infrun.c - ptid_is_pid: new function. I must have written this function 5 times already, using 3 different idioms, across several files, but I haven't contributed any of those. Might as well make it to common code, where it belongs. It returns true if a ptid represents a process. - This was the reason I had added mi_expect_interrupt instead of reusing mi_expect_stop. With this change, since no current target will report a SIGINT on a -exec-interrupt, I can just make it only recognize signal 0. All-in-all, tested on x86-pc-linux-gnu. Does it sound/look sane/OK ? -- Pedro Alves --Boundary-00=_vzq9ICEnJ/xHMte Content-Type: text/x-diff; charset="utf-8"; name="nonstop_stop.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="nonstop_stop.diff" Content-length: 21062 gdb/ 2008-10-16 Pedro Alves * defs.h: Mention ptid_is_pid. * inferior.h (ptid_is_pid): Declare. * gdbthread.h (struct thread_info) : New field. (set_stop_requested): Declare. * infcmd.c (interrupt_target_1): Call set_stop_requested. * infrun.c (clear_proceed_status): Clear stop_requested. (infrun_thread_stop_requested_callback, infrun_thread_stop_requested): New. (handle_inferior_event): If a TARGET_SIGNAL_TRAP is reported on a thread that had an explicit stop request, pretend we got a TARGET_SIGNAL_0. Always stop if the thread had an explicit stop request. (print_stop_reason): In the SIGNAL_RECEIVED case, if we're not outputting to MI, and we got a TARGET_SIGNAL_0, print "# Stopped", instead of mentioning signal 0. (ptid_is_pid): New. * thread.c (set_stop_requested): New. * linux-nat.c (queued_waitpid): Rename to ... (queued_waitpid_1): ... this. Add `peek' argument. Handle it. (queued_waitpid): New, as wrapper to queued_waitpid_1. (push_waitpid): Push the SIGTRAP to the local event queue, to the kernel's. (send_sigint_callback): Delete. (linux_nat_stop_lwp): New. (linux_nat_stop): Use it. gdb/doc/ 2008-10-16 Pedro Alves * observer.texi (thread_stop_requested): New. gdb/testsuite/ 2008-10-16 Pedro Alves * lib/mi-support.exp (mi_expect_interrupt): Expect signal 0 instead of SIGINT. --- gdb/defs.h | 1 gdb/doc/observer.texi | 8 + gdb/gdbthread.h | 10 ++ gdb/infcmd.c | 1 gdb/inferior.h | 3 gdb/infrun.c | 180 ++++++++++++++++++++++++++++++++++----- gdb/linux-nat.c | 128 +++++++++++++++++++++------ gdb/testsuite/lib/mi-support.exp | 2 gdb/thread.c | 25 +++++ 9 files changed, 308 insertions(+), 50 deletions(-) Index: src/gdb/defs.h =================================================================== --- src.orig/gdb/defs.h 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/defs.h 2008-10-16 03:49:30.000000000 +0100 @@ -752,6 +752,7 @@ enum val_prettyprint ptid_get_lwp - Fetch the lwp component of a ptid. ptid_get_tid - Fetch the tid component of a ptid. ptid_equal - Test to see if two ptids are equal. + ptid_is_pid - Test to see if this ptid represents a process id. Please do NOT access the struct ptid members directly (except, of course, in the implementation of the above ptid manipulation Index: src/gdb/inferior.h =================================================================== --- src.orig/gdb/inferior.h 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/inferior.h 2008-10-16 03:49:30.000000000 +0100 @@ -89,6 +89,9 @@ long ptid_get_tid (ptid_t ptid); /* Compare two ptids to see if they are equal */ extern int ptid_equal (ptid_t p1, ptid_t p2); +/* Return true if PTID represents a process id. */ +extern int ptid_is_pid (ptid_t ptid); + /* Save value of inferior_ptid so that it may be restored by a later call to do_cleanups(). Returns the struct cleanup pointer needed for later doing the cleanup. */ Index: src/gdb/gdbthread.h =================================================================== --- src.orig/gdb/gdbthread.h 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/gdbthread.h 2008-10-16 03:49:30.000000000 +0100 @@ -168,6 +168,9 @@ struct thread_info at. */ bpstat stop_bpstat; + /* True if this thread has been explicitly requested to stop. */ + int stop_requested; + /* Private data used by the target vector implementation. */ struct private_thread_info *private; }; @@ -239,6 +242,13 @@ extern void switch_to_thread (ptid_t pti If PIDGET (PTID) is -1, marks all threads. */ extern void set_running (ptid_t ptid, int running); +/* Marks or clears thread(s) PTID as having been requested to stop. + If PTID is MINUS_ONE_PTID, applies to all threads. If + ptid_is_pid(PTID) is true, applies to all threads of the process + pointed at by PTID. If STOP, then the THREAD_STOP_REQUESTED + observer is called with PTID as argument. */ +extern void set_stop_requested (ptid_t ptid, int stop); + /* NOTE: Since the thread state is not a boolean, most times, you do not want to check it with negation. If you really want to check if the thread is stopped, Index: src/gdb/infcmd.c =================================================================== --- src.orig/gdb/infcmd.c 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/infcmd.c 2008-10-16 03:49:30.000000000 +0100 @@ -2169,6 +2169,7 @@ interrupt_target_1 (int all_threads) else ptid = inferior_ptid; target_stop (ptid); + set_stop_requested (ptid, 1); } /* Stop the execution of the target while running in async mode, in Index: src/gdb/infrun.c =================================================================== --- src.orig/gdb/infrun.c 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/infrun.c 2008-10-16 03:53:24.000000000 +0100 @@ -1147,6 +1147,7 @@ clear_proceed_status (void) tp->step_range_end = 0; tp->step_frame_id = null_frame_id; tp->step_over_calls = STEP_OVER_UNDEBUGGABLE; + tp->stop_requested = 0; tp->stop_step = 0; @@ -1519,6 +1520,103 @@ static void keep_going (struct execution static void print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info); +/* Callback for iterate over threads. If the thread is stopped, but + the user/frontend doesn't know about that yet, go through + normal_stop, as if the thread had just stopped now. ARG points at + a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If + ptid_is_pid(PTID) is true, applies to all threads of the process + pointed at by PTID. Otherwise, apply only to the thread pointed by + PTID. */ + +static int +infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) +{ + ptid_t ptid = * (ptid_t *) arg; + + /* If PTID represents a process, then this applies to all its + threads. If PTID is MINUS_ONE_PTID, then apply to all threads. + If */ + if ((ptid_equal (info->ptid, ptid) + || ptid_equal (minus_one_ptid, ptid) + || (ptid_is_pid (ptid) + && ptid_get_pid (ptid) == ptid_get_pid (info->ptid))) + && is_running (info->ptid) + && !is_executing (info->ptid)) + { + struct cleanup *old_chain; + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; + + memset (ecs, 0, sizeof (*ecs)); + + old_chain = make_cleanup_restore_current_thread (); + + switch_to_thread (info->ptid); + + /* Go through handle_inferior_event/normal_stop, so we always + have consistent output as if the stop event had been + reported. */ + ecs->ptid = info->ptid; + ecs->event_thread = find_thread_pid (info->ptid); + ecs->ws.kind = TARGET_WAITKIND_STOPPED; + ecs->ws.value.sig = TARGET_SIGNAL_0; + + handle_inferior_event (ecs); + + if (!ecs->wait_some_more) + { + struct thread_info *tp; + + normal_stop (); + + /* Finish off the continuations. The continations + themselves are responsible for realising the thread + didn't finish what it was supposed to do. */ + tp = inferior_thread (); + do_all_intermediate_continuations_thread (tp); + do_all_continuations_thread (tp); + } + + do_cleanups (old_chain); + } + + return 0; +} + +/* This function is attached as a "thread_stop_requested" observer. + Cleanup local state that assumed the PTID was to be resumed, and + report the stop to the frontend. */ + +void +infrun_thread_stop_requested (ptid_t ptid) +{ + struct displaced_step_request *it, *next, *prev = NULL; + + /* PTID was requested to stop. Remove it from the displaced + stepping queue, so we don't try to resume it automatically. */ + for (it = displaced_step_request_queue; it; it = next) + { + next = it->next; + + if (ptid_equal (it->ptid, ptid) + || ptid_equal (minus_one_ptid, ptid) + || (ptid_is_pid (ptid) + && ptid_get_pid (ptid) == ptid_get_pid (it->ptid))) + { + if (displaced_step_request_queue == it) + displaced_step_request_queue = it->next; + else + prev->next = it->next; + + xfree (it); + } + else + prev = it; + } + + iterate_over_threads (infrun_thread_stop_requested_callback, &ptid); +} + /* Callback for iterate_over_threads. */ static int @@ -2234,11 +2332,21 @@ targets should add new threads to the th return; } - /* Do we need to clean up the state of a thread that has completed a - displaced single-step? (Doing so usually affects the PC, so do - it here, before we set stop_pc.) */ if (ecs->ws.kind == TARGET_WAITKIND_STOPPED) - displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal); + { + /* Do we need to clean up the state of a thread that has + completed a displaced single-step? (Doing so usually affects + the PC, so do it here, before we set stop_pc.) */ + displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal); + + /* If we either finished a single-step or hit a breakpoint, but + the user wanted this thread to be stopped, pretend we got a + SIG0 (generic unsignaled stop). */ + + if (ecs->event_thread->stop_requested + && ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP) + ecs->event_thread->stop_signal = TARGET_SIGNAL_0; + } stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); @@ -2734,9 +2842,11 @@ process_event_stop_test: target_terminal_ours_for_output (); print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal); } - /* Always stop on signals if we're just gaining control of the - program. */ + /* Always stop on signals if we're either just gaining control + of the program, or the user explicitly requested this thread + to remain stopped. */ if (stop_soon != NO_STOP_QUIETLY + || ecs->event_thread->stop_requested || signal_stop_state (ecs->event_thread->stop_signal)) { stop_stepping (ecs); @@ -3750,22 +3860,36 @@ print_stop_reason (enum inferior_stop_re return_child_result_value = stop_info; break; case SIGNAL_RECEIVED: - /* Signal received. The signal table tells us to print about - it. */ + /* Signal received. The signal table tells us to print about + it. */ annotate_signal (); - ui_out_text (uiout, "\nProgram received signal "); - annotate_signal_name (); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED)); - ui_out_field_string (uiout, "signal-name", - target_signal_to_name (stop_info)); - annotate_signal_name_end (); - ui_out_text (uiout, ", "); - annotate_signal_string (); - ui_out_field_string (uiout, "signal-meaning", - target_signal_to_string (stop_info)); - annotate_signal_string_end (); + + if (0 && (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))) + { + struct thread_info *t = inferior_thread (); + + ui_out_text (uiout, "\n["); + ui_out_field_string (uiout, "thread-name", + target_pid_to_str (t->ptid)); + ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num); + ui_out_text (uiout, " stopped"); + } + else + { + ui_out_text (uiout, "\nProgram received signal "); + annotate_signal_name (); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED)); + ui_out_field_string (uiout, "signal-name", + target_signal_to_name (stop_info)); + annotate_signal_name_end (); + ui_out_text (uiout, ", "); + annotate_signal_string (); + ui_out_field_string (uiout, "signal-meaning", + target_signal_to_string (stop_info)); + annotate_signal_string_end (); + } ui_out_text (uiout, ".\n"); break; default: @@ -4672,6 +4796,19 @@ ptid_equal (ptid_t ptid1, ptid_t ptid2) && ptid1.tid == ptid2.tid); } +/* Returns true if PTID represents a process. */ + +int +ptid_is_pid (ptid_t ptid) +{ + if (ptid_equal (minus_one_ptid, ptid)) + return 0; + if (ptid_equal (null_ptid, ptid)) + return 0; + + return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0); +} + /* restore_inferior_ptid() will be used by the cleanup machinery to restore the inferior_ptid value saved in a call to save_inferior_ptid(). */ @@ -4932,4 +5069,5 @@ breakpoints, even if such is supported b displaced_step_ptid = null_ptid; observer_attach_thread_ptid_changed (infrun_thread_ptid_changed); + observer_attach_thread_stop_requested (infrun_thread_stop_requested); } Index: src/gdb/thread.c =================================================================== --- src.orig/gdb/thread.c 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/thread.c 2008-10-16 03:49:30.000000000 +0100 @@ -606,6 +606,31 @@ set_executing (ptid_t ptid, int executin } } +void +set_stop_requested (ptid_t ptid, int stop) +{ + struct thread_info *tp; + int all = ptid_equal (ptid, minus_one_ptid); + + if (all || ptid_is_pid (ptid)) + { + for (tp = thread_list; tp; tp = tp->next) + if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid)) + tp->stop_requested = stop; + } + else + { + tp = find_thread_pid (ptid); + gdb_assert (tp); + tp->stop_requested = stop; + } + + /* Call the stop requested observer so other components of GDB can + react to this request. */ + if (stop) + observer_notify_thread_stop_requested (ptid); +} + /* Prints the list of threads and their details on UIOUT. This is a version of 'info_thread_command' suitable for use from MI. Index: src/gdb/linux-nat.c =================================================================== --- src.orig/gdb/linux-nat.c 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/linux-nat.c 2008-10-16 03:49:30.000000000 +0100 @@ -316,7 +316,6 @@ static void linux_nat_async (void (*call static int linux_nat_async_mask (int mask); static int kill_lwp (int lwpid, int signo); -static int send_sigint_callback (struct lwp_info *lp, void *data); static int stop_callback (struct lwp_info *lp, void *data); /* Captures the result of a successful waitpid call, along with the @@ -333,8 +332,12 @@ struct waitpid_result in the async SIGCHLD handler. */ static struct waitpid_result *waitpid_queue = NULL; +/* Similarly to `waitpid', but check the local event queue instead of + querying the kernel queue. If PEEK, don't remove the event found + from the queue. */ + static int -queued_waitpid (int pid, int *status, int flags) +queued_waitpid_1 (int pid, int *status, int flags, int peek) { struct waitpid_result *msg = waitpid_queue, *prev = NULL; @@ -370,12 +373,6 @@ QWPID: linux_nat_async_events_state(%d), { int pid; - if (prev) - prev->next = msg->next; - else - waitpid_queue = msg->next; - - msg->next = NULL; if (status) *status = msg->status; pid = msg->pid; @@ -383,7 +380,17 @@ QWPID: linux_nat_async_events_state(%d), if (debug_linux_nat_async) fprintf_unfiltered (gdb_stdlog, "QWPID: pid(%d), status(%x)\n", pid, msg->status); - xfree (msg); + + if (!peek) + { + if (prev) + prev->next = msg->next; + else + waitpid_queue = msg->next; + + msg->next = NULL; + xfree (msg); + } return pid; } @@ -396,6 +403,14 @@ QWPID: linux_nat_async_events_state(%d), return -1; } +/* Similarly to `waitpid', but check the local event queue. */ + +static int +queued_waitpid (int pid, int *status, int flags) +{ + return queued_waitpid_1 (pid, status, flags, 0); +} + static void push_waitpid (int pid, int status, int options) { @@ -2200,11 +2215,11 @@ stop_wait_callback (struct lwp_info *lp, /* There was no gdb breakpoint set at pc. Put the event back in the queue. */ if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "SWC: kill %s, %s\n", - target_pid_to_str (lp->ptid), - status_to_str ((int) status)); - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status)); + fprintf_unfiltered (gdb_stdlog, "\ +SWC: leaving SIGTRAP in local queue of %s\n", target_pid_to_str (lp->ptid)); + push_waitpid (GET_LWP (lp->ptid), + W_STOPCODE (SIGTRAP), + lp->cloned ? __WCLONE : 0); } } else @@ -4368,15 +4383,76 @@ linux_nat_async (void (*callback) (enum return; } +/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other + event came out. */ + static int -send_sigint_callback (struct lwp_info *lp, void *data) +linux_nat_stop_lwp (struct lwp_info *lwp, void *data) { - /* Use is_running instead of !lp->stopped, because the lwp may be - stopped due to an internal event, and we want to interrupt it in - that case too. What we want is to check if the thread is stopped - from the point of view of the user. */ - if (is_running (lp->ptid)) - kill_lwp (GET_LWP (lp->ptid), SIGINT); + ptid_t ptid = * (ptid_t *) data; + + if (ptid_equal (lwp->ptid, ptid) + || ptid_equal (minus_one_ptid, ptid) + || (ptid_is_pid (ptid) + && ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid))) + { + if (!lwp->stopped) + { + int pid, status; + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LNSL: running -> suspending %s\n", + target_pid_to_str (lwp->ptid)); + + /* Peek once, to check if we've already waited for this + LWP. */ + pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status, + lwp->cloned ? __WCLONE : 0, 1 /* peek */); + + if (pid == -1) + { + ptid_t ptid = lwp->ptid; + + stop_callback (lwp, NULL); + stop_wait_callback (lwp, NULL); + + /* If the lwp exits while we try to stop it, there's + nothing else to do. */ + lwp = find_lwp_pid (ptid); + if (lwp == NULL) + return 0; + + pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status, + lwp->cloned ? __WCLONE : 0, + 1 /* peek */); + } + + /* If we didn't collect any signal other than SIGSTOP while + stopping the LWP, push a SIGNAL_0 event. In either case, + the event-loop will end up calling target_wait which will + collect these. */ + if (pid == -1) + push_waitpid (ptid_get_lwp (lwp->ptid), W_STOPCODE (0), + lwp->cloned ? __WCLONE : 0); + } + else + { + /* Already known to be stopped; do nothing. */ + + if (debug_linux_nat) + { + if (find_thread_pid (lwp->ptid)->stop_requested) + fprintf_unfiltered (gdb_stdlog, "\ +LNSL: already stopped/stop_requested %s\n", + target_pid_to_str (lwp->ptid)); + else + fprintf_unfiltered (gdb_stdlog, "\ +LNSL: already stopped/no stop_requested yet %s\n", + target_pid_to_str (lwp->ptid)); + } + } + } return 0; } @@ -4385,13 +4461,9 @@ linux_nat_stop (ptid_t ptid) { if (non_stop) { - if (ptid_equal (ptid, minus_one_ptid)) - iterate_over_lwps (send_sigint_callback, &ptid); - else - { - struct lwp_info *lp = find_lwp_pid (ptid); - send_sigint_callback (lp, NULL); - } + linux_nat_async_events (sigchld_sync); + iterate_over_lwps (linux_nat_stop_lwp, &ptid); + target_async (inferior_event_handler, 0); } else linux_ops->to_stop (ptid); Index: src/gdb/doc/observer.texi =================================================================== --- src.orig/gdb/doc/observer.texi 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/doc/observer.texi 2008-10-16 03:49:30.000000000 +0100 @@ -135,6 +135,14 @@ The thread specified by @var{t} has been The thread specified by @var{t} has exited. @end deftypefun +@deftypefun void thread_stop_requested (ptid_t @var{ptid}) +An explicit stop request was issued to @var{ptid}. If @var{ptid} +equals @var{minus_one_ptid}, the request applied to all threads. If +@code{ptid_is_pid(ptid)} returns true, the request applied to all +threads of the process pointed at by @var{ptid}. Otherwise, the +request applied to the single thread pointed at by @var{ptid}. +@end deftypefun + @deftypefun void target_resumed (ptid_t @var{ptid}) The target was resumed. The @var{ptid} parameter specifies which thread was resume, and may be RESUME_ALL if all threads are resumed. Index: src/gdb/testsuite/lib/mi-support.exp =================================================================== --- src.orig/gdb/testsuite/lib/mi-support.exp 2008-10-16 03:49:29.000000000 +0100 +++ src/gdb/testsuite/lib/mi-support.exp 2008-10-16 03:49:30.000000000 +0100 @@ -1050,7 +1050,7 @@ proc mi_expect_interrupt { test } { set prompt_re "$mi_gdb_prompt$" } - set r "reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\"" + set r "reason=\"signal-received\",signal-name=\"0\",signal-meaning=\"Signal 0\"" set any "\[^\n\]*" --Boundary-00=_vzq9ICEnJ/xHMte--