public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Simon Marchi <simon.marchi@polymtl.ca>
To: Pedro Alves <pedro@palves.net>, gdb-patches@sourceware.org
Subject: Re: [PATCH 11/12] detach in all-stop with threads running
Date: Wed, 13 Jan 2021 01:55:25 -0500	[thread overview]
Message-ID: <9486d54e-341b-3e54-a684-52850703e1f1@polymtl.ca> (raw)
In-Reply-To: <20210113011543.2047449-12-pedro@palves.net>



On 2021-01-12 8:15 p.m., Pedro Alves wrote:
> A following patch will add a testcase that has a number of threads
> constantly stepping over a breakpoint, and then has GDB detach the
> process, while threads are running.  If we have more then one inferior

"more than"

> running, and we detach from just one of the inferiors, we expect that
> the remaining inferior continues running.  However, in all-stop, if
> GDB needs to pause the target for the detach, nothing is re-resuming
> the other inferiors after the detach.  "info threads" shows the
> threads as running, but they really aren't.  This fixes it.
> 
> gdb/ChangeLog:
> 
> 	* infcmd.c (detach_command): Hold strong reference to target, and
> 	if all-stop on entry, restart threads on exit.
> 	* infrun.c (switch_back_to_stepped_thread): Factor out bits to ...
> 	(restart_stepped_thread): ... this new function.  Also handle
> 	trap_expected.
> 	(restart_after_all_stop_detach): New function.
> 	* infrun.h (restart_after_all_stop_detach): Declare.
> ---
>  gdb/infcmd.c |  13 ++++
>  gdb/infrun.c | 163 +++++++++++++++++++++++++++++++++++----------------
>  gdb/infrun.h |   4 ++
>  3 files changed, 128 insertions(+), 52 deletions(-)
> 
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 6f0ed952de6..ebaf57592ef 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -2750,6 +2750,16 @@ detach_command (const char *args, int from_tty)
>  
>    disconnect_tracing ();
>  
> +  /* Hold a strong reference to the target while (maybe)
> +     detaching the parent.  Otherwise detaching could close the
> +     target.  */
> +  auto target_ref
> +    = target_ops_ref::new_reference (current_inferior ()->process_target ());
> +
> +  /* Save this before detaching, since detaching may unpush the
> +     process_stratum target.  */
> +  bool was_non_stop_p = target_is_non_stop_p ();
> +
>    target_detach (current_inferior (), from_tty);
>  
>    /* The current inferior process was just detached successfully.  Get
> @@ -2766,6 +2776,9 @@ detach_command (const char *args, int from_tty)
>  
>    if (deprecated_detach_hook)
>      deprecated_detach_hook ();
> +
> +  if (!was_non_stop_p)
> +    restart_after_all_stop_detach (as_process_stratum_target (target_ref.get ()));
>  }
>  
>  /* Disconnect from the current target without resuming it (leaving it
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 4a17410fcd6..4f1a16d2c60 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -7098,6 +7098,9 @@ process_event_stop_test (struct execution_control_state *ecs)
>    keep_going (ecs);
>  }
>  
> +static bool restart_stepped_thread (process_stratum_target *resume_target,
> +				    ptid_t resume_ptid);
> +
>  /* In all-stop mode, if we're currently stepping but have stopped in
>     some other thread, we may need to switch back to the stepped
>     thread.  Returns true we set the inferior running, false if we left
> @@ -7108,8 +7111,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
>  {
>    if (!target_is_non_stop_p ())
>      {
> -      struct thread_info *stepping_thread;
> -
>        /* If any thread is blocked on some internal breakpoint, and we
>  	 simply need to step over that breakpoint to get it going
>  	 again, do that first.  */
> @@ -7172,78 +7173,136 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
>        if (!signal_program[ecs->event_thread->suspend.stop_signal])
>  	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
>  
> -      /* Do all pending step-overs before actually proceeding with
> -	 step/next/etc.  */
> -      if (start_step_over ())
> +      if (restart_stepped_thread (ecs->target, ecs->ptid))
>  	{
>  	  prepare_to_wait (ecs);
>  	  return true;
>  	}
>  
> -      /* Look for the stepping/nexting thread.  */
> -      stepping_thread = NULL;
> +      switch_to_thread (ecs->event_thread);
> +    }
>  
> -      for (thread_info *tp : all_non_exited_threads ())
> -	{
> -	  switch_to_thread_no_regs (tp);
> +  return false;
> +}
>  
> -	  /* Ignore threads of processes the caller is not
> -	     resuming.  */
> -	  if (!sched_multi
> -	      && (tp->inf->process_target () != ecs->target
> -		  || tp->inf->pid != ecs->ptid.pid ()))
> -	    continue;
> +/* Look for the thread that was stepping, and resume it.
> +   RESUME_TARGET / RESUME_PTID indicate the set of threads the caller
> +   is resuming.  Return true if a thread was started, false
> +   otherwise.  */
>  
> -	  /* When stepping over a breakpoint, we lock all threads
> -	     except the one that needs to move past the breakpoint.
> -	     If a non-event thread has this set, the "incomplete
> -	     step-over" check above should have caught it earlier.  */
> -	  if (tp->control.trap_expected)
> -	    {
> -	      internal_error (__FILE__, __LINE__,
> -			      "[%s] has inconsistent state: "
> -			      "trap_expected=%d\n",
> -			      target_pid_to_str (tp->ptid).c_str (),
> -			      tp->control.trap_expected);
> -	    }
> +static bool
> +restart_stepped_thread (process_stratum_target *resume_target,
> +			ptid_t resume_ptid)
> +{
> +  /* Do all pending step-overs before actually proceeding with
> +     step/next/etc.  */
> +  if (start_step_over ())
> +    return true;
>  
> -	  /* Did we find the stepping thread?  */
> -	  if (tp->control.step_range_end)
> -	    {
> -	      /* Yep.  There should only one though.  */
> -	      gdb_assert (stepping_thread == NULL);
> +  for (thread_info *tp : all_threads_safe ())
> +    {
> +      if (tp->state == THREAD_EXITED)
> +	continue;
> +
> +      if (tp->suspend.waitstatus_pending_p)
> +	continue;
>  
> -	      /* The event thread is handled at the top, before we
> -		 enter this loop.  */
> -	      gdb_assert (tp != ecs->event_thread);
> +      /* Ignore threads of processes the caller is not
> +	 resuming.  */
> +      if (!sched_multi
> +	  && (tp->inf->process_target () != resume_target
> +	      || tp->inf->pid != resume_ptid.pid ()))
> +	continue;
>  
> -	      /* If some thread other than the event thread is
> -		 stepping, then scheduler locking can't be in effect,
> -		 otherwise we wouldn't have resumed the current event
> -		 thread in the first place.  */
> -	      gdb_assert (!schedlock_applies (tp));
> +      if (tp->control.trap_expected)
> +	{
> +	  infrun_debug_printf ("switching back to stepped thread (step-over)");
>  
> -	      stepping_thread = tp;
> -	    }
> +	  if (keep_going_stepped_thread (tp))
> +	    return true;
>  	}
> +    }
> +
> +  for (thread_info *tp : all_threads_safe ())
> +    {
> +      if (tp->state == THREAD_EXITED)
> +	continue;
> +
> +      if (tp->suspend.waitstatus_pending_p)
> +	continue;
>  
> -      if (stepping_thread != NULL)
> +      /* Ignore threads of processes the caller is not
> +	 resuming.  */
> +      if (!sched_multi
> +	  && (tp->inf->process_target () != resume_target
> +	      || tp->inf->pid != resume_ptid.pid ()))
> +	continue;
> +
> +      /* Did we find the stepping thread?  */
> +      if (tp->control.step_range_end)
>  	{
> -	  infrun_debug_printf ("switching back to stepped thread");
> +	  infrun_debug_printf ("switching back to stepped thread (stepping)");
>  
> -	  if (keep_going_stepped_thread (stepping_thread))
> -	    {
> -	      prepare_to_wait (ecs);
> -	      return true;
> -	    }
> +	  if (keep_going_stepped_thread (tp))
> +	    return true;
>  	}
> -
> -      switch_to_thread (ecs->event_thread);
>      }
>  
>    return false;
>  }
>  
> +/* See infrun.h.  */
> +
> +void
> +restart_after_all_stop_detach (process_stratum_target *proc_target)
> +{
> +  /* Note we don't check target_is_non_stop_p() here, because the
> +     current inferior may no longer have a process_stratum target
> +     pushed, as we just detached.  */
> +
> +  /* See if we have a THREAD_RUNNING thread that need to be
> +     re-resumed.  If we have any thread that is already executing,
> +     then we don't need to resume the target -- it is already been
> +     resumed.  With the remote target (in all-stop), it's even
> +     impossible to issue another resumption if the target is already
> +     resumed, until the target reports a stop.  */
> +  for (thread_info *thr : all_threads (proc_target))
> +    {
> +      if (thr->state != THREAD_RUNNING)
> +	continue;
> +
> +      /* If we have any thread that is already executing, then we
> +	 don't need to resume the target -- it is already been
> +	 resumed.  */
> +      if (thr->executing)
> +	return;
> +
> +      /* If we have a pending event to process, skip resuming the
> +	 target and go straight to processing it.  */
> +      if (thr->resumed && thr->suspend.waitstatus_pending_p)
> +	return;
> +    }

Hmm instead of that loop, could you do an early check in the function
instead, like

  if (proc_target->threads_executing)
    return;

? When a thread gets target-resumed, the thr->executing flag gets set
at the same time as the proc_target->threads_executing flag.  And when
resume_1-ing a thread with a pending status,
proc_target->threads_executing also gets set.  So maybe (just maybe)
that whole loop could be replaced with that check.

But otherwise, that LGTM.

Simon

  reply	other threads:[~2021-01-13  6:55 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-13  1:15 [PATCH 00/12] Fix detach + displaced-step regression + N bugs more Pedro Alves
2021-01-13  1:15 ` [PATCH 01/12] Fix attaching in non-stop mode Pedro Alves
2021-01-13  3:11   ` Simon Marchi
2021-02-03  1:21     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 02/12] Fix "target extended-remote" + "maint set target-non-stop" + "attach" Pedro Alves
2021-01-13  5:01   ` Simon Marchi
2021-01-13  1:15 ` [PATCH 03/12] Testcase for attaching in non-stop mode Pedro Alves
2021-01-13  5:09   ` Simon Marchi
2021-02-03  1:23     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 04/12] Fix a couple vStopped pending ack bugs Pedro Alves
2021-01-13  5:29   ` Simon Marchi
2021-02-03  1:25     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 05/12] gdbserver: spurious SIGTRAP w/ detach while step-over in progress Pedro Alves
2021-01-13  6:00   ` Simon Marchi
2021-02-03  1:26     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 06/12] Factor out after-stop event handling code from stop_all_threads Pedro Alves
2021-01-13  6:06   ` Simon Marchi
2021-02-03  1:26     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 07/12] prepare_for_detach: don't release scoped_restore at the end Pedro Alves
2021-01-13  6:08   ` Simon Marchi
2021-02-03  1:27     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 08/12] prepare_for_detach and ongoing displaced stepping Pedro Alves
2021-01-13  6:23   ` Simon Marchi
2021-01-13  1:15 ` [PATCH 09/12] detach and breakpoint removal Pedro Alves
2021-01-13  6:32   ` Simon Marchi
2021-02-03  1:28     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 10/12] detach with in-line step over in progress Pedro Alves
2021-01-13  6:39   ` Simon Marchi
2021-01-13  1:15 ` [PATCH 11/12] detach in all-stop with threads running Pedro Alves
2021-01-13  6:55   ` Simon Marchi [this message]
2021-02-03  1:31     ` Pedro Alves
2021-07-12 15:36   ` Jonah Graham
2021-07-12 19:36     ` Pedro Alves
2021-01-13  1:15 ` [PATCH 12/12] Testcase for detaching while stepping over breakpoint Pedro Alves
2021-01-13  7:05   ` Simon Marchi
2021-02-03  1:33     ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9486d54e-341b-3e54-a684-52850703e1f1@polymtl.ca \
    --to=simon.marchi@polymtl.ca \
    --cc=gdb-patches@sourceware.org \
    --cc=pedro@palves.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).