diff --git a/gdb/infrun.c b/gdb/infrun.c index e5f8dc8d8ab..329b6e1dd28 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -4239,7 +4239,12 @@ reinstall_readline_callback_handler_cleanup () } /* Clean up the FSMs of threads that are now stopped. In non-stop, - that's just the event thread. In all-stop, that's all threads. */ + that's just the event thread. In all-stop, that's all threads. In + all-stop, threads that had a pending exit no longer have a reason + to be around, as their FSMs/commands are canceled, so we delete + them. This avoids "info threads" listing such threads as if they + were alive (and failing to read their registers), the user being to + select and resume them (and that failing), etc. */ static void clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) @@ -4257,15 +4262,28 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) { scoped_restore_current_thread restore_thread; - for (thread_info *thr : all_non_exited_threads ()) + for (thread_info *thr : all_threads_safe ()) { - if (thr->thread_fsm () == nullptr) + if (thr->state == THREAD_EXITED) continue; + if (thr == ecs->event_thread) continue; - switch_to_thread (thr); - thr->thread_fsm ()->clean_up (thr); + if (thr->thread_fsm () != nullptr) + { + switch_to_thread (thr); + thr->thread_fsm ()->clean_up (thr); + } + + /* As we are cancelling the command/FSM of this thread, + whatever was the reason we needed to report a thread + exited event to the user, that reason is gone. Delete + the thread, so that the user doesn't see it in the thread + list, the next proceed doesn't try to resume it, etc. */ + if (thr->has_pending_waitstatus () + && thr->pending_waitstatus ().kind () == TARGET_WAITKIND_THREAD_EXITED) + delete_thread (thr); } } } @@ -5591,6 +5609,9 @@ handle_inferior_event (struct execution_control_state *ecs) if (ecs->ws.kind () == TARGET_WAITKIND_THREAD_EXITED) { + ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid); + gdb_assert (ecs->event_thread != nullptr); + delete_thread (ecs->event_thread); prepare_to_wait (ecs); return; } diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 816a5a0491c..e97d2262f7f 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -898,10 +898,11 @@ linux_nat_switch_fork (ptid_t new_ptid) registers_changed (); } -/* Handle the exit of a single thread LP. */ +/* Handle the exit of a single thread LP. If DEL_THREAD is true, + delete the thread_info associated to LP, if it exists. */ static void -exit_lwp (struct lwp_info *lp) +exit_lwp (struct lwp_info *lp, bool del_thread = true) { struct thread_info *th = find_thread_ptid (linux_target, lp->ptid); @@ -911,7 +912,8 @@ exit_lwp (struct lwp_info *lp) gdb_printf (_("[%s exited]\n"), target_pid_to_str (lp->ptid).c_str ()); - delete_thread (th); + if (del_thread) + delete_thread (th); } delete_lwp (lp->ptid); @@ -3138,11 +3140,17 @@ filter_exit_event (struct lwp_info *event_child, if (!is_leader (event_child)) { if (report_thread_events) - ourstatus->set_thread_exited (0); + { + ourstatus->set_thread_exited (0); + /* Delete lwp, but not thread_info, infrun will need it to + process the event. */ + exit_lwp (event_child, false); + } else - ourstatus->set_ignore (); - - exit_lwp (event_child); + { + ourstatus->set_ignore (); + exit_lwp (event_child); + } } return ptid; diff --git a/gdb/netbsd-nat.c b/gdb/netbsd-nat.c index 64f74c9405c..37f2fa49b0b 100644 --- a/gdb/netbsd-nat.c +++ b/gdb/netbsd-nat.c @@ -629,7 +629,6 @@ nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, if (print_thread_events) gdb_printf (_("[%s exited]\n"), target_pid_to_str (wptid).c_str ()); - delete_thread (thr); } /* The GDB core expects that the rest of the threads are running. */