]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Move deleting thread on TARGET_WAITKIND_THREAD_EXITED to core
authorPedro Alves <pedro@palves.net>
Mon, 5 Dec 2022 20:44:39 +0000 (20:44 +0000)
committerPedro Alves <pedro@palves.net>
Fri, 10 Mar 2023 19:14:18 +0000 (19:14 +0000)
Currently, infrun assumes that when TARGET_WAITKIND_THREAD_EXITED is
reported, the corresponding GDB thread has already been removed from
the GDB thread list.

Later in the series, that will no longer work, as infrun will need to
refer to the thread's thread_info when it processes
TARGET_WAITKIND_THREAD_EXITED.

As preparation, this patch makes deleting the GDB thread
responsibility of infrun, instead of the target.

Change-Id: I013d87f61ffc9aaca49f0d6ce2a43e3ea69274de

gdb/infrun.c
gdb/linux-nat.c
gdb/netbsd-nat.c

index e5f8dc8d8abef327c376820e10731a11d2da1faf..329b6e1dd28fb6edd432e9c5203ab48ebf9a6db8 100644 (file)
@@ -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;
     }
index 816a5a0491c9d496123947f8bb2378f6a92904cd..e97d2262f7f7ee270d1e6895ef608a7ac06ddab8 100644 (file)
@@ -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;
index 64f74c9405c98c72c3606587c27369ab6dccc748..37f2fa49b0bad14e69333d87b8e6e78a793a0917 100644 (file)
@@ -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.  */