From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-il1-x133.google.com (mail-il1-x133.google.com [IPv6:2607:f8b0:4864:20::133]) by sourceware.org (Postfix) with ESMTPS id 333DA3858439 for ; Wed, 3 Aug 2022 13:08:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 333DA3858439 Received: by mail-il1-x133.google.com with SMTP id s16so4779974ilp.3 for ; Wed, 03 Aug 2022 06:08:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=FLfWInPou4r6gRDrcWgkFAcYrSIhMpFm6nDari+PzKc=; b=fFuEz6Z+vQecbWw0LX+nMAuxVK4QldpZE7nsGwq6hj11jTHOKH/e1E9mh0iujR2+b/ UjgHqBVPwPprC6UcIXP2bN4FfWcewzixQWEwy99CCfhzTzG24NKmxtOJ8Hc4akmkNILW rKn1OfyqyV5vhw2dAdaxnE7VuaIT7RJn25YhI1MO4OM6ND5v9oIc2ck5bBYqqjPCQOia Bl87AycLSRdmG0rSu+gp7bIR3fxoQuAuHRf1QnOKKu+nvPikvbNRHJRiHJj9tYNhPDTD l106pgRC4pEksMPq3F1vW7W5s00rlmAk8vjX+FSHOEJLUBFF4b5LBln4EmBJGa1JzPZs vg9A== X-Gm-Message-State: ACgBeo2Y9eWK//68IG5KuL0rN4OvUpM9y3B9uHk/Iy+KhwrfufHLbjyI qSBJ/275Wavbc0y/g/pptWgPSxFT997R7w== X-Google-Smtp-Source: AA6agR6rIfP9BIEMBg/OmjIjnGRGWkxz04eWZvvSQK9wJHDn94/anPNl0HXfEVGzt/MDdVovl78lzA== X-Received: by 2002:a92:c264:0:b0:2de:bf95:118a with SMTP id h4-20020a92c264000000b002debf95118amr5004097ild.160.1659532108393; Wed, 03 Aug 2022 06:08:28 -0700 (PDT) Received: from murgatroyd.Home (71-211-185-228.hlrn.qwest.net. [71.211.185.228]) by smtp.gmail.com with ESMTPSA id h14-20020a02b60e000000b0033ebbb649fasm7631057jam.101.2022.08.03.06.08.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Aug 2022 06:08:27 -0700 (PDT) From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH 2/2] Implement target async for Windows Date: Wed, 3 Aug 2022 07:08:22 -0600 Message-Id: <20220803130822.735057-3-tromey@adacore.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220803130822.735057-1-tromey@adacore.com> References: <20220803130822.735057-1-tromey@adacore.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Wed, 03 Aug 2022 13:08:31 -0000 This implements target async for Windows. The basic idea is to have the worker thread block in WaitForDebugEvent, then notify the event loop when an event is seen. In a few situations, this blocking behavior is undesirable, so the functions passed to do_synchronously are changed to return a boolean indicating which behavior is needed. --- gdb/windows-nat.c | 123 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 15 deletions(-) diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 80cdedce7b9..9c277e9a93d 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #ifdef __CYGWIN__ @@ -72,6 +73,8 @@ #include "gdbsupport/gdb_wait.h" #include "nat/windows-nat.h" #include "gdbsupport/symbol.h" +#include "ser-event.h" +#include "inf-loop.h" using namespace windows_nat; @@ -315,6 +318,23 @@ struct windows_nat_target final : public x86_nat_target return disable_randomization_available (); } + bool can_async_p () override + { + return true; + } + + bool is_async_p () override + { + return m_is_async; + } + + void async (bool enable) override; + + int async_wait_fd () override + { + return serial_event_fd (m_wait_event); + } + private: windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb, @@ -322,7 +342,8 @@ struct windows_nat_target final : public x86_nat_target void delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p); DWORD fake_create_process (); - BOOL windows_continue (DWORD continue_status, int id, int killed); + BOOL windows_continue (DWORD continue_status, int id, int killed, + bool last_call = false); /* This function implements the background thread that starts inferiors and waits for events. */ @@ -332,8 +353,9 @@ struct windows_nat_target final : public x86_nat_target until it has been called. On Windows, certain debugging functions can only be called by the thread that started (or attached to) the inferior. These are all done in the worker - thread, via calls to this method. */ - void do_synchronously (gdb::function_view func); + thread, via calls to this method. If FUNC returns true, + process_thread will wait for debug events when FUNC returns. */ + void do_synchronously (gdb::function_view func); /* This waits for a debug event, dispatching to the worker thread as needed. */ @@ -341,7 +363,7 @@ struct windows_nat_target final : public x86_nat_target /* Queue used to send requests to process_thread. This is implicitly locked. */ - std::queue> m_queue; + std::queue> m_queue; /* Event used to signal process_thread that an item has been pushed. */ @@ -349,6 +371,18 @@ struct windows_nat_target final : public x86_nat_target /* Event used by process_thread to indicate that it has processed a single function call. */ HANDLE m_response_event; + + /* Serial event used to communicate wait event availability to the + main loop. */ + serial_event *m_wait_event; + + /* The last debug event, when M_WAIT_EVENT has been set. */ + DEBUG_EVENT m_last_debug_event {}; + /* True if a debug event is pending. */ + std::atomic m_debug_event_pending { false }; + + /* True if currently in async mode. */ + bool m_is_async = false; }; static windows_nat_target the_windows_nat_target; @@ -366,7 +400,8 @@ check (BOOL ok, const char *file, int line) windows_nat_target::windows_nat_target () : m_pushed_event (CreateEvent (nullptr, false, false, nullptr)), - m_response_event (CreateEvent (nullptr, false, false, nullptr)) + m_response_event (CreateEvent (nullptr, false, false, nullptr)), + m_wait_event (make_serial_event ()) { auto fn = [] (LPVOID self) -> DWORD { @@ -378,6 +413,23 @@ windows_nat_target::windows_nat_target () CloseHandle (bg_thread); } +void +windows_nat_target::async (bool enable) +{ + if (enable == is_async_p ()) + return; + + if (enable) + add_file_handler (async_wait_fd (), + [] (int, gdb_client_data) + { + inferior_event_handler (INF_REG_EVENT); + }, + nullptr, "windows_nat_target"); + else + delete_file_handler (async_wait_fd ()); +} + /* A wrapper for WaitForSingleObject that issues a warning if something unusual happens. */ static void @@ -407,16 +459,26 @@ windows_nat_target::process_thread () { wait_for_single (m_pushed_event, INFINITE); - gdb::function_view func = std::move (m_queue.front ()); + gdb::function_view func = std::move (m_queue.front ()); m_queue.pop (); - func (); + bool should_wait = func (); SetEvent (m_response_event); + + if (should_wait) + { + if (!m_debug_event_pending) + { + wait_for_debug_event (&m_last_debug_event, INFINITE); + m_debug_event_pending = true; + } + serial_event_set (m_wait_event); + } } } void -windows_nat_target::do_synchronously (gdb::function_view func) +windows_nat_target::do_synchronously (gdb::function_view func) { m_queue.emplace (std::move (func)); SetEvent (m_pushed_event); @@ -428,7 +490,15 @@ windows_nat_target::wait_for_debug_event_main_thread (DEBUG_EVENT *event) { do_synchronously ([&] () { - wait_for_debug_event (event, INFINITE); + if (m_debug_event_pending) + { + *event = m_last_debug_event; + m_debug_event_pending = false; + serial_event_clear (m_wait_event); + } + else + wait_for_debug_event (event, INFINITE); + return false; }); } @@ -1178,14 +1248,23 @@ windows_per_inferior::handle_access_violation /* Resume thread specified by ID, or all artificially suspended threads, if we are continuing execution. KILLED non-zero means we have killed the inferior, so we should ignore weird errors due to - threads shutting down. */ + threads shutting down. LAST_CALL is true if we expect this to be + the last call to continue the inferior -- we are either mourning it + or detaching. */ BOOL -windows_nat_target::windows_continue (DWORD continue_status, int id, int killed) +windows_nat_target::windows_continue (DWORD continue_status, int id, + int killed, bool last_call) { windows_process.desired_stop_thread_id = id; if (windows_process.matching_pending_stop (debug_events)) - return TRUE; + { + /* There's no need to really continue, because there's already + another event pending. However, we do need to inform the + event loop of this. */ + serial_event_set (m_wait_event); + return TRUE; + } for (auto &th : windows_process.thread_list) if (id == -1 || id == (int) th->tid) @@ -1263,6 +1342,9 @@ windows_nat_target::windows_continue (DWORD continue_status, int id, int killed) { if (!continue_last_debug_event (continue_status, debug_events)) err = (unsigned) GetLastError (); + /* On the last call, do not block waiting for an event that will + never come. */ + return !last_call; }); if (err.has_value ()) @@ -1506,6 +1588,12 @@ windows_nat_target::get_windows_debug_event windows_process.last_sig = GDB_SIGNAL_0; DEBUG_EVENT *current_event = &windows_process.current_event; + if ((options & TARGET_WNOHANG) != 0 && !m_debug_event_pending) + { + ourstatus->set_ignore (); + return minus_one_ptid; + } + wait_for_debug_event_main_thread (&windows_process.current_event); continue_status = DBG_CONTINUE; @@ -1991,6 +2079,8 @@ windows_nat_target::attach (const char *args, int from_tty) if (!ok) err = (unsigned) GetLastError (); + + return true; }); if (err.has_value ()) @@ -2019,8 +2109,7 @@ windows_nat_target::attach (const char *args, int from_tty) void windows_nat_target::detach (inferior *inf, int from_tty) { - ptid_t ptid = minus_one_ptid; - resume (ptid, 0, GDB_SIGNAL_0); + windows_continue (DBG_CONTINUE, -1, 0, true); gdb::optional err; do_synchronously ([&] () @@ -2029,6 +2118,7 @@ windows_nat_target::detach (inferior *inf, int from_tty) err = (unsigned) GetLastError (); else DebugSetProcessKillOnExit (FALSE); + return false; }); if (err.has_value ()) @@ -2594,6 +2684,7 @@ windows_nat_target::create_inferior (const char *exec_file, disable_randomization, &si, &pi)) ret = (unsigned) GetLastError (); + return true; }); if (w32_env) @@ -2723,6 +2814,7 @@ windows_nat_target::create_inferior (const char *exec_file, &si, &pi)) ret = (unsigned) GetLastError (); + return true; }); if (tty != INVALID_HANDLE_VALUE) CloseHandle (tty); @@ -2760,7 +2852,7 @@ windows_nat_target::create_inferior (const char *exec_file, void windows_nat_target::mourn_inferior () { - (void) windows_continue (DBG_CONTINUE, -1, 0); + (void) windows_continue (DBG_CONTINUE, -1, 0, true); x86_cleanup_dregs(); if (windows_process.open_process_used) { @@ -2845,6 +2937,7 @@ void windows_nat_target::close () { DEBUG_EVENTS ("inferior_ptid=%d\n", inferior_ptid.pid ()); + async (false); } /* Convert pid to printable format. */ -- 2.34.1