aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/infrun.c32
-rw-r--r--gdb/linux-nat.c21
2 files changed, 41 insertions, 12 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 03eb32a..e1e761c 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4352,7 +4352,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
+ able to select and resume them (and that failing), etc. */
static void
clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
@@ -4370,15 +4375,29 @@ 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);
}
}
}
@@ -5728,6 +5747,9 @@ handle_inferior_event (struct execution_control_state *ecs)
if (ecs->ws.kind () == TARGET_WAITKIND_THREAD_EXITED)
{
+ ecs->event_thread = ecs->target->find_thread (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 5bbdabc..1e224e0 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -898,14 +898,15 @@ 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 = linux_target->find_thread (lp->ptid);
- if (th)
+ if (th != nullptr && del_thread)
delete_thread (th);
delete_lwp (lp->ptid);
@@ -3155,11 +3156,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;