From 0d5b594f86aa7c8f38487802f75841460ab705bf Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 17 Mar 2016 10:21:37 +0000 Subject: PR remote/19496, timeout in forking-threads-plus-bkpt This patch addresses a failure in gdb.threads/forking-threads-plus-breakpoint.exp: FAIL: gdb.threads/forking-threads-plus-breakpoint.exp: cond_bp_target=1: detach_on_fork=on: inferior 1 exited (timeout) Cause: A fork event was reported to GDB before GDB knew about the parent thread, followed immediately by a breakpoint event in a different thread. The parent thread was subsequently added via remote_notice_new_inferior in process_stop_reply, but when the thread was added the thread_info.state was set to THREAD_STOPPED. The fork event was then handled correctly, but when the fork parent was resumed via a call to keep_going, the state was unchanged. The breakpoint event was then handled, which caused all the non-breakpoint threads to be stopped. When the breakpoint thread was resumed, all the non-breakpoint threads were resumed via infrun.c:restart_threads. Our old fork parent wasn't restarted, because it still had thread_info.state set to THREAD_STOPPED. Ultimately the program under debug hung waiting for a pthread_join while the old fork parent was stopped forever by GDB. Fix: Since this is non-stop, then the bug is that the thread should have been added in THREAD_RUNNING state. Consider that infrun may be pulling target events out of the target_ops backend into its own event queue, but, not process them immediately. E.g., infrun may be stopping all threads temporarily for a step-over-breakpoint operation for thread A (stop_all_threads). The waitstatus of all threads is thus left pending in the thread structure (save_status), including the fork event of thread B. Right at this point, if the user does "info threads", that should show thread B (the fork parent) running, not stopped, even if internally, gdb is holding it paused for a little bit. Thus if in non-stop mode, always add new threads in the external user-visible THREAD_RUNNING state. Change remote_notice_new_inferior to accept the internal executing state of the thread instead, with EXECUTING set to 1 when we discover a thread that is running on the target (such as through remote_update_thread_list), and 0 when the thread is really paused (such as when we see a stop reply). Tested on x86_64 Linux and Nios II Linux target with x86 Linux host. gdb/ChangeLog: 2016-03-17 Pedro Alves Don Breazeal PR remote/19496 * infcmd.c (notice_new_inferior): Use the 'leave_running' argument instead of checking the 'non_stop' global. * remote.c (remote_add_thread): New parameter 'executing'. Use it to set the new thread's executing state. (remote_notice_new_inferior): Rename parameter 'running' to 'executing'. Always set the thread state to THREAD_RUNNING in non-stop mode, and to THREAD_STOPPED in all-stop mode. Pass EXECUTING to remote_add_thread and notice_new_inferior. (remote_update_thread_list): Update to pass executing state, not running state. --- gdb/infcmd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'gdb/infcmd.c') diff --git a/gdb/infcmd.c b/gdb/infcmd.c index a80bf0a..d687116 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -2903,11 +2903,7 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty) old_chain = make_cleanup (null_cleanup, NULL); - /* If in non-stop, leave threads as running as they were. If - they're stopped for some reason other than us telling it to, the - target reports a signal != GDB_SIGNAL_0. We don't try to - resume threads with such a stop signal. */ - mode = non_stop ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING; + mode = leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING; if (!ptid_equal (inferior_ptid, null_ptid)) make_cleanup_restore_current_thread (); @@ -2943,7 +2939,6 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty) return; } - mode = leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING; attach_post_wait ("" /* args */, from_tty, mode); do_cleanups (old_chain); -- cgit v1.1