From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id 9141F385840D for ; Fri, 21 Jan 2022 20:16:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9141F385840D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from ralph.baldwin.cx (ralph.baldwin.cx [66.234.199.215]) by mail.baldwin.cx (Postfix) with ESMTPSA id D17FC1A84E20 for ; Fri, 21 Jan 2022 15:16:42 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH v5 09/15] fbsd-nat: Implement async target support. Date: Fri, 21 Jan 2022 12:16:25 -0800 Message-Id: <20220121201631.63530-10-jhb@FreeBSD.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220121201631.63530-1-jhb@FreeBSD.org> References: <20220121201631.63530-1-jhb@FreeBSD.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Fri, 21 Jan 2022 15:16:43 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Jan 2022 20:16:46 -0000 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 | 154 ++++++++++++++++++++++++++++++++++++++++++++++++- gdb/fbsd-nat.h | 12 ++++ 2 files changed, 164 insertions(+), 2 deletions(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index c485fff6ed4..1ed7092fece 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -18,7 +18,10 @@ along with this program. If not, see . */ #include "defs.h" +#include "gdbsupport/block-signals.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" @@ -28,6 +31,7 @@ #include "gdbthread.h" #include "gdbsupport/buildargv.h" #include "gdbsupport/gdb_wait.h" +#include "inf-loop.h" #include "inf-ptrace.h" #include #ifdef HAVE_SYS_PROCCTL_H @@ -927,6 +931,114 @@ 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 () +{ + /* This flag should be checked in the common target.c code. */ + gdb_assert (target_async_permitted); + + /* Otherwise, this targets is always able to support async mode. */ + return true; +} + +/* 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. */ + gdb::block_signals blocker; + + 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 (); + } +} + +/* 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 @@ -998,6 +1110,11 @@ static void fbsd_add_vfork_done (ptid_t pid) { fbsd_pending_vfork_done.push_front (pid); + + /* If we're in async mode, need to tell the event loop there's + something here to process. */ + if (target_is_async_p ()) + fbsd_nat_event_pipe.mark (); } /* Check for a pending vfork done event for a specific PID. */ @@ -1166,8 +1283,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; @@ -1382,6 +1499,36 @@ 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 + && ourstatus->kind() != TARGET_WAITKIND_NO_RESUMED) + || ptid != minus_one_ptid)) + fbsd_nat_event_pipe.mark (); + + fbsd_nat_debug_printf ("returning [%s], [%s]", + target_pid_to_str (wptid).c_str (), + ourstatus->to_string ().c_str ()); + return wptid; +} + #ifdef USE_SIGTRAP_SIGINFO /* Implement the "stopped_by_sw_breakpoint" target_ops method. */ @@ -1676,4 +1823,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 6f8b206dcd5..4ac8faad4df 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; @@ -110,6 +120,8 @@ class fbsd_nat_target : public inf_ptrace_target void post_startup_inferior (ptid_t) 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.34.1