[PATCH v2 08/13] fbsd-nat: Implement async target support.

Andrew Burgess aburgess@redhat.com
Wed Nov 24 15:00:47 GMT 2021


* John Baldwin <jhb@FreeBSD.org> [2021-08-03 11:49:55 -0700]:

> This is a fairly simple version of async target support.
> 
> Synchronous mode still uses blocking waitpid() calls in
> inf_ptrace::wait() unlike the Linux native target which always uses
> WNOHANG and uses sigsuspend() for synchronous operation.
> 
> Asynchronous mode registers an event pipe with the core as a file
> handle and writes to the pipe when SIGCHLD is raised.  TARGET_WNOHANG
> is handled by inf_ptrace::wait().
> ---
>  gdb/fbsd-nat.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  gdb/fbsd-nat.h |  12 ++++
>  2 files changed, 165 insertions(+), 2 deletions(-)
> 
> diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
> index 0ae1195791c..36ce00164dd 100644
> --- a/gdb/fbsd-nat.c
> +++ b/gdb/fbsd-nat.c
> @@ -19,14 +19,18 @@
>  
>  #include "defs.h"
>  #include "gdbsupport/byte-vector.h"
> +#include "gdbsupport/event-loop.h"
> +#include "gdbsupport/event-pipe.h"
>  #include "gdbcore.h"
>  #include "inferior.h"
>  #include "regcache.h"
>  #include "regset.h"
>  #include "gdbarch.h"
>  #include "gdbcmd.h"
> +#include "gdbsupport/gdb-sigmask.h"
>  #include "gdbthread.h"
>  #include "gdbsupport/gdb_wait.h"
> +#include "inf-loop.h"
>  #include "inf-ptrace.h"
>  #include <sys/types.h>
>  #ifdef HAVE_SYS_PROCCTL_H
> @@ -925,6 +929,118 @@ fbsd_nat_target::update_thread_list ()
>  #endif
>  }
>  
> +/* Async mode support.  */
> +
> +static event_pipe fbsd_nat_event_pipe;
> +
> +/* Implement the "can_async_p" target method.  */
> +
> +bool
> +fbsd_nat_target::can_async_p ()
> +{
> +  /* Use async unless the user explicitly prevented it via the "maint
> +     set target-async" command.  */
> +  return target_async_permitted;
> +}

With this patch:

  https://sourceware.org/pipermail/gdb-patches/2021-November/183764.html

which is not merged yet, this can be changed to:

    bool
    fbsd_nat_target::can_async_p ()
    {
      assert (target_async_permitted);
      return true;
    }

I'm happy to make this change if this work gets merged first - I'm
just noting this here.

> +
> +/* Implement the "is_async_p" target method.  */
> +
> +bool
> +fbsd_nat_target::is_async_p ()
> +{
> +  return fbsd_nat_event_pipe.is_open ();
> +}
> +
> +/* Implement the "async_wait_fd" target method.  */
> +
> +int
> +fbsd_nat_target::async_wait_fd ()
> +{
> +  return fbsd_nat_event_pipe.event_fd ();
> +}
> +
> +/* SIGCHLD handler notifies the event-loop in async mode.  */
> +
> +static void
> +sigchld_handler (int signo)
> +{
> +  int old_errno = errno;
> +
> +  if (fbsd_nat_event_pipe.is_open ())
> +    fbsd_nat_event_pipe.mark ();
> +
> +  errno = old_errno;
> +}
> +
> +/* Callback registered with the target events file descriptor.  */
> +
> +static void
> +handle_target_event (int error, gdb_client_data client_data)
> +{
> +  inferior_event_handler (INF_REG_EVENT);
> +}
> +
> +/* Implement the "async" target method.  */
> +
> +void
> +fbsd_nat_target::async (int enable)
> +{
> +  if ((enable != 0) == is_async_p ())
> +    return;
> +
> +  /* Block SIGCHILD while we create/destroy the pipe, as the handler
> +     writes to it.  */
> +
> +  sigset_t chld_mask, prev_mask;
> +  sigemptyset (&chld_mask);
> +  sigaddset (&chld_mask, SIGCHLD);
> +  gdb_sigmask (SIG_BLOCK, &chld_mask, &prev_mask);
> +
> +  if (enable)
> +    {
> +      if (!fbsd_nat_event_pipe.open ())
> +	internal_error (__FILE__, __LINE__, "failed to create event pipe.");
> +
> +      add_file_handler (fbsd_nat_event_pipe.event_fd (),
> +			handle_target_event, NULL, "fbsd-nat");
> +
> +      /* Trigger a poll in case there are pending events to
> +	 handle.  */
> +      fbsd_nat_event_pipe.mark ();
> +    }
> +  else
> +    {
> +      delete_file_handler (fbsd_nat_event_pipe.event_fd ());
> +      fbsd_nat_event_pipe.close ();
> +    }
> +
> +  gdb_sigmask (SIG_SETMASK, &prev_mask, NULL);
> +}
> +
> +/* Implement the "close" target method.  */
> +
> +void
> +fbsd_nat_target::close ()
> +{
> +  if (is_async_p ())
> +    async (0);
> +
> +  inf_ptrace_target::close ();
> +}
> +
> +/* Implement the "attach" target method.  */
> +
> +void
> +fbsd_nat_target::attach (const char *args, int from_tty)
> +{
> +  inf_ptrace_target::attach (args, from_tty);
> +
> +  /* Curiously, the core does not do this automatically.  */
> +  if (target_can_async_p ())
> +    target_async (1);
> +}
> +
> +
>  #ifdef TDP_RFPPWAIT
>  /*
>    To catch fork events, PT_FOLLOW_FORK is set on every traced process
> @@ -1164,8 +1280,8 @@ fbsd_handle_debug_trap (fbsd_nat_target *target, ptid_t ptid,
>     the status in *OURSTATUS.  */
>  
>  ptid_t
> -fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
> -		       target_wait_flags target_options)
> +fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
> +			 target_wait_flags target_options)
>  {
>    ptid_t wptid;
>  
> @@ -1377,6 +1493,33 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
>      }
>  }
>  
> +ptid_t
> +fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
> +		       target_wait_flags target_options)
> +{
> +  ptid_t wptid;
> +
> +  fbsd_nat_debug_printf ("[%s], [%s]", target_pid_to_str (ptid).c_str (),
> +			 target_options_to_string (target_options).c_str ());
> +
> +  /* Ensure any subsequent events trigger a new event in the loop.  */
> +  if (is_async_p ())
> +    fbsd_nat_event_pipe.flush ();
> +
> +  wptid = wait_1 (ptid, ourstatus, target_options);
> +
> +  /* If we are in async mode and found an event, there may still be
> +     another event pending.  Trigger the event pipe so that that the
> +     event loop keeps polling until no event is returned.  */
> +  if (is_async_p () && ourstatus->kind != TARGET_WAITKIND_IGNORE)
> +    fbsd_nat_event_pipe.mark ();

I notice you use a different condition here to the one present in
linux-nat.c, specifically, if you get an event of type
TARGET_WAITKIND_NO_RESUMED, you'll remark the pipe, while Linux
doesn't.

Is there a reason for this difference?

> +
> +  fbsd_nat_debug_printf ("returning [%s], [%s]",
> +			 target_pid_to_str (wptid).c_str (),
> +			 target_waitstatus_to_string (ourstatus).c_str ());
> +  return wptid;
> +}
> +
>  #ifdef USE_SIGTRAP_SIGINFO
>  /* Implement the "stopped_by_sw_breakpoint" target_ops method.  */
>  
> @@ -1510,6 +1653,11 @@ fbsd_nat_target::follow_fork (ptid_t child_ptid, target_waitkind fork_kind,
>  	  /* Schedule a fake VFORK_DONE event to report on the next
>  	     wait.  */
>  	  fbsd_add_vfork_done (inferior_ptid);
> +
> +	  /* If we're in async mode, need to tell the event loop
> +	     there's something here to process.  */
> +	  if (is_async_p ())
> +	    fbsd_nat_event_pipe.mark ();

If feels like this marking of the event pipe should be within
fbsd_add_vfork_done maybe?  The two actions, queuing the fake event,
and marking the async event pipe are tightly coupled, right?

I guess you might need to make fbsd_add_vfork_done a private member
function so you can easily call is_async_p(), or just call
'target_is_async_p()' instead.

Thanks,
Andrew

>  	}
>  #endif
>      }
> @@ -1667,4 +1815,7 @@ Enables printf debugging output."),
>  			   NULL,
>  			   &show_fbsd_nat_debug,
>  			   &setdebuglist, &showdebuglist);
> +
> +  /* Install a SIGCHLD handler.  */
> +  signal (SIGCHLD, sigchld_handler);
>  }
> diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h
> index 3fb502ca8d0..9dd9017c1c3 100644
> --- a/gdb/fbsd-nat.h
> +++ b/gdb/fbsd-nat.h
> @@ -66,9 +66,19 @@ class fbsd_nat_target : public inf_ptrace_target
>  
>    void update_thread_list () override;
>  
> +  bool can_async_p () override;
> +  bool is_async_p () override;
> +
> +  int async_wait_fd () override;
> +  void async (int) override;
> +
> +  void close () override;
> +
>    thread_control_capabilities get_thread_control_capabilities () override
>    { return tc_schedlock; }
>  
> +  void attach (const char *, int) override;
> +
>    void create_inferior (const char *, const std::string &,
>  			char **, int) override;
>  
> @@ -107,6 +117,8 @@ class fbsd_nat_target : public inf_ptrace_target
>    bool supports_disable_randomization () override;
>  
>  private:
> +  ptid_t wait_1 (ptid_t, struct target_waitstatus *, target_wait_flags);
> +
>    /* Helper routines for use in fetch_registers and store_registers in
>       subclasses.  These routines fetch and store a single set of
>       registers described by REGSET.  The REGSET's 'regmap' field must
> -- 
> 2.31.1
> 



More information about the Gdb-patches mailing list