gdb: move clearing of tp->pending_follow to follow_fork_inferior
authorSimon Marchi <simon.marchi@efficios.com>
Wed, 1 Dec 2021 14:40:03 +0000 (09:40 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Thu, 9 Dec 2021 02:00:39 +0000 (21:00 -0500)
A following patch will change targets so that when they detach an
inferior, they also detach any pending fork children this inferior may
have.  While doing this, I hit a case where we couldn't differentiate
two cases, where in one we should detach the fork detach but not in the
other.

Suppose we continue past a fork with "follow-fork-mode == child" &&
"detach-on-fork on".  follow_fork_inferior calls target_detach to detach
the parent.  In that case the target should not detach the fork
child, as we'll continue debugging the child.  As of now, the
tp->pending_follow field of the thread who called fork still contains
the details about the fork.

Then, suppose we run to a fork catchpoint and the user types "detach".
In that case, the target should detach the fork child in addition to the
parent.  In that case as well, the tp->pending_follow field contains
the details about the fork.

To allow targets to differentiate the two cases, clear
tp->pending_follow a bit earlier, when following a fork.  Targets will
then see that tp->pending_follow contains TARGET_WAITKIND_SPURIOUS, and
won't detach the fork child.

As of this patch, no behavior changes are expected.

Change-Id: I537741859ed712cb531baaefc78bb934e2a28153

gdb/infrun.c

index e4739ed14f665d43b78ffdece9fa086ab731cf95..a1264f77f9bf2db3842107a753e94f75d658db58 100644 (file)
@@ -601,6 +601,23 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   if (child_inf != nullptr)
     gdb_assert (!child_inf->thread_list.empty ());
 
+  /* Clear the parent thread's pending follow field.  Do this before calling
+     target_detach, so that the target can differentiate the two following
+     cases:
+
+      - We continue past a fork with "follow-fork-mode == child" &&
+       "detach-on-fork on", and therefore detach the parent.  In that
+       case the target should not detach the fork child.
+      - We run to a fork catchpoint and the user types "detach".  In that
+       case, the target should detach the fork child in addition to the
+       parent.
+
+     The former case will have pending_follow cleared, the later will have
+     pending_follow set.  */
+  thread_info *parent_thread = find_thread_ptid (parent_inf, parent_ptid);
+  gdb_assert (parent_thread != nullptr);
+  parent_thread->pending_follow.set_spurious ();
+
   /* Detach the parent if needed.  */
   if (follow_child)
     {
@@ -668,7 +685,6 @@ follow_fork ()
 {
   bool follow_child = (follow_fork_mode_string == follow_fork_mode_child);
   bool should_resume = true;
-  struct thread_info *tp;
 
   /* Copy user stepping state to the new inferior thread.  FIXME: the
      followed fork child thread should have a copy of most of the
@@ -714,7 +730,7 @@ follow_fork ()
        }
     }
 
-  tp = inferior_thread ();
+  thread_info *tp = inferior_thread ();
 
   /* If there were any forks/vforks that were caught and are now to be
      followed, then do so now.  */
@@ -768,14 +784,6 @@ follow_fork ()
          }
        else
          {
-           /* This pending follow fork event is now handled, one way
-              or another.  The previous selected thread may be gone
-              from the lists by now, but if it is still around, need
-              to clear the pending follow request.  */
-           tp = find_thread_ptid (parent_targ, parent);
-           if (tp)
-             tp->pending_follow.set_spurious ();
-
            /* This makes sure we don't try to apply the "Switched
               over from WAIT_PID" logic above.  */
            nullify_last_target_wait_ptid ();