From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id uW5pC1563WiejBsAWB0awg (envelope-from ) for ; Wed, 01 Oct 2025 15:00:46 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; secure) header.d=adacore.com header.i=@adacore.com header.a=rsa-sha256 header.s=google header.b=S3rkGAf6; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 28CF91E0B6; Wed, 01 Oct 2025 15:00:46 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 7343F1E04C for ; Wed, 01 Oct 2025 15:00:44 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0BBC13858D20 for ; Wed, 1 Oct 2025 19:00:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0BBC13858D20 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=adacore.com header.i=@adacore.com header.a=rsa-sha256 header.s=google header.b=S3rkGAf6 Received: from mail-il1-x136.google.com (mail-il1-x136.google.com [IPv6:2607:f8b0:4864:20::136]) by sourceware.org (Postfix) with ESMTPS id DD1533858D33 for ; Wed, 1 Oct 2025 18:57:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DD1533858D33 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DD1533858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::136 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759345072; cv=none; b=RvkuOGPBhosLlYX1SGeIaeg7BLrd/4Hdiuiye59gK6k3cjayG0f4/8klYQYuUwxzXc+zV8V+RnVOstmWfaszmDZUusRGVh0kT/taDQgOIsP7GescI3j10VPyuzU99Qcg84ZIIagaj5zUZUjE0Yd1rk+gZ4MeMXDHBs57J2EIB4Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1759345072; c=relaxed/simple; bh=wqAV21fc+Nc+F4zET1jj04NtBXVLglN81AWX3oEy/UQ=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=HFlPFIbVwIUJEUyorQe15t7oGfcdduaElIhwftNEFegZ4gI+mGq+/25UkvErVykKz7RkmILFstvl06HT3oxw9bIYAIlU+sUYVtYTUxvPB6Z2tf1YskapSylkZl29Fu5ImmMJ97sSPzOMNThoIyM20INDYH0oyoTFWe62b+mTZSE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DD1533858D33 Received: by mail-il1-x136.google.com with SMTP id e9e14a558f8ab-42a1145f626so797015ab.3 for ; Wed, 01 Oct 2025 11:57:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1759345071; x=1759949871; darn=sourceware.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=1yGVOYAP7rO+yWwBNTNEBZ/FzfkXwDq9OjutDeM1lxA=; b=S3rkGAf6w0YQhoWRyVvGFQfw8EJd71k7JU+uFU1b0T2TPOmxQO/n+wcgM0v2CBUbcc +3UcW/nMsSoaRwAh+ZrqFAJKXuytlhyDovI3Hggx5XCcnjQpHfGukV82ox83Cnr10xFk tKy4RFr4KCoQ0LUqUJQ7ND4bx2ylUyTY+DrvTJpzAs6fLw0SKmCqsyQGQTacs8oCo4WM GhN/HGDp7MsYziUhKlucubhZiXArzV9eX7h9aeBGYYHfM1UskGQyxZvAQ3aNPUM8QXZP urdSbLaizJmFcboIE1zHq8sVkgQPd0f3Y+SnDofYhOqtbjPSDDCHGP2CmSRVfE9c6gje NnNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759345071; x=1759949871; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1yGVOYAP7rO+yWwBNTNEBZ/FzfkXwDq9OjutDeM1lxA=; b=WFLwfxVJdIDkPxTbXhhvDM03KI8u8MGC709T4r7aNMgeDKWRstvH6NBhmV8yKDJb96 qiwfbjCP6g93KHff5RWGrKDN7KmFwO9ploLSjoCO+Nc/e5gDSSxynlhgy6RRcZBjDWaR NJMjet0KC5faNQEGjr4Zqu4tdnNkbnElpFjdM3o/9I1oEmlsNAz9JTJ1lcuYUeFxiVzV /erA7flaNuEIRuRrX9SIQkAAV8ICFBXEhdcnFb9W4y8YCPNElGv+bA0ZWjqnNODfNttB oaqXBzNWGXnFnzg6zW5q/d5kJJlxJ14yh5N7aBhi39SjocOO2ulnxDn5xomnzoEbroEb jzuA== X-Gm-Message-State: AOJu0YyBbdj/m1T/R112h2Ic3Ql0DWbRFLJRydqCDHpgNOcLvvR8w/9T +nxlqD39lA2LXypVz5KCrBbNu31JL9WpAiCtJNpVFRV1awIKDk+1jZYSaau92dQQsA== X-Gm-Gg: ASbGncsfB1G0kQPHnWW+ZBoaQikYwBZ7wBxume/xsdp1sDsq1RFmrEvLRUfzA6jOJnv fRuzgCtGEwJ2SpR0ahgytxxR5t/p2qy90/IYPPGgpXNR9PLstm1ynLov7yArSrz05NwD14yvmY/ 8er8RP3RvMF+80dRf9GznNA9k22zs3ZjunDTqaEzRs9qRPVY9nqisZCA1zwllThDrVE0opp0xuo M++q96wE0YhrA2eSGMZW2RZer/BCkTLQmzpnyBVeUanzax9ZIbsLzuNc36VR6EuNpoS44u9q6o9 vfNZv8v6euEzxW6f8wVqCKne4qdvOS0KPfqUiROHGtEIPP4c6dizLvWslqKIiTF+HMLmJGkvroO fLn1G5DttK8ziVt4FSs1/7JApeIQSdIkhzgwkybnBAE2KgXU1S3zGQyST8QjlCLD/gkTCu9xMjv Hy X-Google-Smtp-Source: AGHT+IGEaiZQXGIbjuDEqliyrRF6IKAGczt7Sq+URyqPBOMtkYsScRVN2Vx/C7IvAFSfTUq+eaqH5Q== X-Received: by 2002:a05:6e02:188b:b0:426:b592:7978 with SMTP id e9e14a558f8ab-42d8167e87fmr63418005ab.25.1759345070537; Wed, 01 Oct 2025 11:57:50 -0700 (PDT) Received: from [192.168.0.26] (97-122-110-68.hlrn.qwest.net. [97.122.110.68]) by smtp.gmail.com with ESMTPSA id 8926c6da1cb9f-57b5ec4aa7dsm83970173.65.2025.10.01.11.57.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Oct 2025 11:57:50 -0700 (PDT) From: Tom Tromey Date: Wed, 01 Oct 2025 12:57:49 -0600 Subject: [PATCH 3/3] Introduce gdbsupport/cxx-thread.h and use it MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20251001-isolate-cxx-thread-v1-3-4bb740be2467@adacore.com> References: <20251001-isolate-cxx-thread-v1-0-4bb740be2467@adacore.com> In-Reply-To: <20251001-isolate-cxx-thread-v1-0-4bb740be2467@adacore.com> To: gdb-patches@sourceware.org Cc: Tom Tromey X-Mailer: b4 0.14.2 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org This introduces a new file, gdbsupport/cxx-thread.h, which provides stubs for the C++ threading functionality on systems that don't support it. On fully-working ports, this header just supplies a number of aliases in the gdb namespace. So, for instance, gdb::mutex is just an alias for std::mutex. For non-working ports, compatibility stubs are provided for the subset of threading functionality that's used in gdb. These generally do nothing and assume single-threaded operation. The idea behind this is to reduce the number of checks of CXX_STD_THREAD, making the code cleaner. Not all spots using CXX_STD_THREAD could readily be converted. In particular: * Unit tests * --config output * Code manipulating threads themselves * The extension interrupting handling code These all seem fine to me. Note there's also a check in py-dap.c. This one is perhaps slightly subtle: DAP starts threads on the Python side, but it relies on gdb itself being thread-savvy, for instance in gdb.post_event. --- gdb/complaints.c | 16 +-- gdb/dwarf2/cooked-index-worker.c | 17 +-- gdb/dwarf2/cooked-index-worker.h | 17 +-- gdb/dwarf2/read.c | 35 ++---- gdb/dwarf2/read.h | 8 +- gdb/gdb_bfd.c | 47 ++------ gdb/minsyms.c | 37 ++---- gdb/run-on-main-thread.c | 38 ++---- gdbsupport/cxx-thread.h | 243 +++++++++++++++++++++++++++++++++++++++ gdbsupport/thread-pool.h | 91 +-------------- 10 files changed, 297 insertions(+), 252 deletions(-) diff --git a/gdb/complaints.c b/gdb/complaints.c index 3c7f9bc7c89604de766672ef0f4c78005ed7d83b..03d27d615a58e6e5e7d89cda951bbbb2ae9c53a2 100644 --- a/gdb/complaints.c +++ b/gdb/complaints.c @@ -22,11 +22,9 @@ #include "cli/cli-cmds.h" #include "run-on-main-thread.h" #include "top.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/selftest.h" #include "gdbsupport/unordered_map.h" -#if CXX_STD_THREAD -#include -#endif /* Map format strings to counters. */ @@ -38,9 +36,7 @@ static gdb::unordered_map counters; int stop_whining = 0; -#if CXX_STD_THREAD -static std::mutex complaint_mutex; -#endif /* CXX_STD_THREAD */ +static gdb::mutex complaint_mutex; /* See complaints.h. */ @@ -50,9 +46,7 @@ complaint_internal (const char *fmt, ...) va_list args; { -#if CXX_STD_THREAD - std::lock_guard guard (complaint_mutex); -#endif + gdb::lock_guard guard (complaint_mutex); if (++counters[fmt] > stop_whining) return; } @@ -126,9 +120,7 @@ re_emit_complaints (const complaint_collection &complaints) void complaint_interceptor::warn (const char *fmt, va_list args) { -#if CXX_STD_THREAD - std::lock_guard guard (complaint_mutex); -#endif + gdb::lock_guard guard (complaint_mutex); g_complaint_interceptor->m_complaints.insert (string_vprintf (fmt, args)); } diff --git a/gdb/dwarf2/cooked-index-worker.c b/gdb/dwarf2/cooked-index-worker.c index 09d80eff629c4d168e3108e5ee5d9bd082be6543..abaf41fb00c315e2e3261d0293e25faed4a147c9 100644 --- a/gdb/dwarf2/cooked-index-worker.c +++ b/gdb/dwarf2/cooked-index-worker.c @@ -132,9 +132,8 @@ bool cooked_index_worker::wait (cooked_state desired_state, bool allow_quit) { bool done; -#if CXX_STD_THREAD { - std::unique_lock lock (m_mutex); + gdb::unique_lock lock (m_mutex); /* This may be called from a non-main thread -- this functionality is needed for the index cache -- but in this case we require @@ -146,7 +145,7 @@ cooked_index_worker::wait (cooked_state desired_state, bool allow_quit) if (allow_quit) { std::chrono::milliseconds duration { 15 }; - if (m_cond.wait_for (lock, duration) == std::cv_status::timeout) + if (m_cond.wait_for (lock, duration) == gdb::cv_status::timeout) QUIT; } else @@ -154,11 +153,6 @@ cooked_index_worker::wait (cooked_state desired_state, bool allow_quit) } done = m_state == cooked_state::CACHE_DONE; } -#else - /* Without threads, all the work is done immediately on the main - thread, and there is never anything to wait for. */ - done = desired_state == cooked_state::CACHE_DONE; -#endif /* CXX_STD_THREAD */ /* Only the main thread is allowed to report complaints and the like. */ @@ -213,15 +207,10 @@ cooked_index_worker::set (cooked_state desired_state) { gdb_assert (desired_state != cooked_state::INITIAL); -#if CXX_STD_THREAD - std::lock_guard guard (m_mutex); + gdb::lock_guard guard (m_mutex); gdb_assert (desired_state > m_state); m_state = desired_state; m_cond.notify_one (); -#else - /* Without threads, all the work is done immediately on the main - thread, and there is never anything to do. */ -#endif /* CXX_STD_THREAD */ } /* See cooked-index-worker.h. */ diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h index dfdc82f52744ec36e626ab883d31a5d44071b063..4213b4e12b7214520f3856494777bee8aa9e2e01 100644 --- a/gdb/dwarf2/cooked-index-worker.h +++ b/gdb/dwarf2/cooked-index-worker.h @@ -27,11 +27,7 @@ #include "dwarf2/read.h" #include "maint.h" #include "run-on-main-thread.h" - -#if CXX_STD_THREAD -#include -#include -#endif /* CXX_STD_THREAD */ +#include "gdbsupport/cxx-thread.h" using cutu_reader_up = std::unique_ptr; @@ -300,11 +296,9 @@ class cooked_index_worker /* Result of each worker task. */ std::vector m_results; -#if CXX_STD_THREAD /* Mutex to synchronize access to M_RESULTS when workers append their result. */ - std::mutex m_results_mutex; -#endif /* CXX_STD_THREAD */ + gdb::mutex m_results_mutex; /* Any warnings emitted. For the time being at least, this only needed in do_reading, not in every worker. Note that @@ -317,13 +311,12 @@ class cooked_index_worker parent relationships. */ parent_map_map m_all_parents_map; -#if CXX_STD_THREAD /* Current state of this object. */ cooked_state m_state = cooked_state::INITIAL; /* Mutex and condition variable used to synchronize. */ - std::mutex m_mutex; - std::condition_variable m_cond; -#endif /* CXX_STD_THREAD */ + gdb::mutex m_mutex; + gdb::condition_variable m_cond; + /* This flag indicates whether any complaints or exceptions that arose during scanning have been reported by 'wait'. This may only be modified on the main thread. */ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 05f8452895a0d7e2f7e53a3c45c5a0317d27c995..6618b2242ff8e6106e81a3d72cac504725be561d 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -605,10 +605,8 @@ struct dwp_file dwo_unit_set loaded_cus; dwo_unit_set loaded_tus; -#if CXX_STD_THREAD /* Mutex to synchronize access to LOADED_CUS and LOADED_TUS. */ - std::mutex loaded_cutus_lock; -#endif + gdb::mutex loaded_cutus_lock; /* Table to map ELF section numbers to their sections. This is only needed for the DWP V1 file format. */ @@ -3327,9 +3325,7 @@ class cooked_index_worker_debug_info : public cooked_index_worker m_thread_storage.done_reading (m_complaint_handler.release ()); /* Append the results of this worker to the parent instance. */ -#if CXX_STD_THREAD - std::lock_guard lock (m_parent->m_results_mutex); -#endif + gdb::lock_guard lock (m_parent->m_results_mutex); m_parent->m_results.emplace_back (std::move (m_thread_storage)); } @@ -6318,12 +6314,8 @@ static dwo_file * lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name, const char *comp_dir) { -#if CXX_STD_THREAD - std::lock_guard guard (per_bfd->dwo_files_lock); -#endif - + gdb::lock_guard guard (per_bfd->dwo_files_lock); auto it = per_bfd->dwo_files.find (dwo_file_search {dwo_name, comp_dir}); - return it != per_bfd->dwo_files.end () ? it->get() : nullptr; } @@ -6338,10 +6330,7 @@ lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name, static dwo_file * add_dwo_file (dwarf2_per_bfd *per_bfd, dwo_file_up dwo_file) { -#if CXX_STD_THREAD - std::lock_guard lock (per_bfd->dwo_files_lock); -#endif - + gdb::lock_guard lock (per_bfd->dwo_files_lock); return per_bfd->dwo_files.emplace (std::move (dwo_file)).first->get (); } @@ -7473,10 +7462,7 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, = is_debug_types ? dwp_file->loaded_tus : dwp_file->loaded_cus; { -#if CXX_STD_THREAD - std::lock_guard guard (dwp_file->loaded_cutus_lock); -#endif - + gdb::lock_guard guard (dwp_file->loaded_cutus_lock); if (auto it = dwo_unit_set.find (signature); it != dwo_unit_set.end ()) return it->get (); @@ -7511,10 +7497,7 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, /* If another thread raced with this one, opening the exact same DWO unit, then we'll keep that other thread's copy. */ -#if CXX_STD_THREAD - std::lock_guard guard (dwp_file->loaded_cutus_lock); -#endif - + gdb::lock_guard guard (dwp_file->loaded_cutus_lock); auto it = dwo_unit_set.emplace (std::move (dwo_unit)).first; return it->get (); } @@ -7594,12 +7577,10 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp, return NULL; { -#if CXX_STD_THREAD /* The operations below are not thread-safe, use a lock to synchronize concurrent accesses. */ - static std::mutex mutex; - std::lock_guard lock (mutex); -#endif + static gdb::mutex mutex; + gdb::lock_guard lock (mutex); if (!bfd_check_format (sym_bfd.get (), bfd_object)) return NULL; diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 2f9ad05b792bfeeb059229274fd43d2dc6ebc3d3..f0d46f6acc6cd95381c53c7b21876df9b2087661 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -20,9 +20,6 @@ #ifndef GDB_DWARF2_READ_H #define GDB_DWARF2_READ_H -#if CXX_STD_THREAD -#include -#endif #include #include "dwarf2/abbrev.h" #include "dwarf2/unit-head.h" @@ -32,6 +29,7 @@ #include "dwarf2/section.h" #include "dwarf2/cu.h" #include "dwarf2/dwz.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/gdb_obstack.h" #include "gdbsupport/function-view.h" #include "gdbsupport/packed.h" @@ -618,10 +616,8 @@ struct dwarf2_per_bfd /* Set of dwo_file objects. */ dwo_file_up_set dwo_files; -#if CXX_STD_THREAD /* Mutex to synchronize access to DWO_FILES. */ - std::mutex dwo_files_lock; -#endif + gdb::mutex dwo_files_lock; /* The DWP file if there is one, or NULL. */ dwp_file_up dwp_file; diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c index 2e477eba6a9b8f31c558aeb6d37cdeeed369a6e6..4c641fe4c7b88094003b47ca77040b533f039453 100644 --- a/gdb/gdb_bfd.c +++ b/gdb/gdb_bfd.c @@ -33,18 +33,15 @@ #include "gdbsupport/fileio.h" #include "inferior.h" #include "cli/cli-style.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/unordered_map.h" #include "gdbsupport/unordered_set.h" -#if CXX_STD_THREAD - -#include - /* Lock held when doing BFD operations. A recursive mutex is used because we use this mutex internally and also for BFD, just to make life a bit simpler, and we may sometimes hold it while calling into BFD. */ -static std::recursive_mutex gdb_bfd_mutex; +static gdb::recursive_mutex gdb_bfd_mutex; /* BFD locking function. */ @@ -64,8 +61,6 @@ gdb_bfd_unlock (void *ignore) return true; } -#endif /* CXX_STD_THREAD */ - /* An object of this type is stored in the section's user data when mapping a section. */ @@ -153,7 +148,6 @@ struct gdb_bfd_data /* The registry. */ registry registry_fields; -#if CXX_STD_THREAD /* Most of the locking needed for multi-threaded operation is handled by BFD itself. However, the current BFD model is that locking is only needed for global operations -- but it turned out @@ -163,8 +157,7 @@ struct gdb_bfd_data This lock is the fix: wrappers for important BFD functions will acquire this lock before performing operations that might modify the state of this BFD. */ - std::mutex per_bfd_mutex; -#endif + gdb::mutex per_bfd_mutex; }; registry * @@ -548,9 +541,7 @@ gdb_bfd_open (const char *name, const char *target, int fd, name += strlen (TARGET_SYSROOT_PREFIX); } -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); if (fd == -1) { @@ -677,9 +668,7 @@ gdb_bfd_ref (struct bfd *abfd) if (abfd == NULL) return; -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd); @@ -709,9 +698,7 @@ gdb_bfd_unref (struct bfd *abfd) if (abfd == NULL) return; -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd); gdb_assert (gdata->refc >= 1); @@ -779,10 +766,8 @@ gdb_bfd_map_section (asection *sectp, bfd_size_type *size) abfd = sectp->owner; -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); descriptor = get_section_descriptor (sectp); @@ -1115,10 +1100,8 @@ bool gdb_bfd_get_full_section_contents (bfd *abfd, asection *section, gdb::byte_vector *contents) { -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); bfd_size_type section_size = bfd_section_size (section); @@ -1133,10 +1116,8 @@ gdb_bfd_get_full_section_contents (bfd *abfd, asection *section, int gdb_bfd_stat (bfd *abfd, struct stat *sbuf) { -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); return bfd_stat (abfd, sbuf); } @@ -1146,10 +1127,8 @@ gdb_bfd_stat (bfd *abfd, struct stat *sbuf) long gdb_bfd_get_mtime (bfd *abfd) { -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); return bfd_get_mtime (abfd); } @@ -1290,9 +1269,7 @@ get_bfd_inferior_data (struct inferior *inf) static unsigned long increment_bfd_error_count (const std::string &str) { -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); struct bfd_inferior_data *bid = get_bfd_inferior_data (current_inferior ()); auto &map = bid->bfd_error_string_counts; @@ -1337,9 +1314,7 @@ gdb_bfd_init () { if (bfd_init () == BFD_INIT_MAGIC) { -#if CXX_STD_THREAD if (bfd_thread_init (gdb_bfd_lock, gdb_bfd_unlock, nullptr)) -#endif return; } diff --git a/gdb/minsyms.c b/gdb/minsyms.c index d3a8d670d1b5b8daa3266b69a371ba197ec2aba8..c23d170663744a03bda2a7ccec7e3a0763aace60 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -51,13 +51,10 @@ #include "cli/cli-utils.h" #include "gdbsupport/symbol.h" #include +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/parallel-for.h" #include "inferior.h" -#if CXX_STD_THREAD -#include -#endif - /* Return true if MINSYM is a cold clone symbol. Recognize f.i. these symbols (mangled/demangled): - _ZL3foov.cold @@ -1398,18 +1395,13 @@ class minimal_symbol_install_worker minimal_symbol_install_worker (minimal_symbol *msymbols, gdb::array_view hash_values, - objfile_per_bfd_storage *per_bfd -#if CXX_STD_THREAD - , std::mutex &demangled_mutex -#endif - ) + objfile_per_bfd_storage *per_bfd, + gdb::mutex &demangled_mutex) : m_time_it ("minsym install worker"), m_msymbols (msymbols), m_hash_values (hash_values), - m_per_bfd (per_bfd) -#if CXX_STD_THREAD - , m_demangled_mutex (demangled_mutex) -#endif + m_per_bfd (per_bfd), + m_demangled_mutex (demangled_mutex) {} void operator() (iterator_range msym_range) noexcept @@ -1447,9 +1439,7 @@ class minimal_symbol_install_worker { /* To limit how long we hold the lock, we only acquire it here and not while we demangle the names above. */ -#if CXX_STD_THREAD - std::lock_guard guard (m_demangled_mutex); -#endif + gdb::lock_guard guard (m_demangled_mutex); for (minimal_symbol &msym : msym_range) { size_t idx = &msym - m_msymbols; @@ -1467,9 +1457,7 @@ class minimal_symbol_install_worker minimal_symbol *m_msymbols; gdb::array_view m_hash_values; objfile_per_bfd_storage *m_per_bfd; -#if CXX_STD_THREAD - std::mutex &m_demangled_mutex; -#endif + gdb::mutex &m_demangled_mutex; }; /* Add the minimal symbols in the existing bunches to the objfile's official @@ -1549,11 +1537,9 @@ minimal_symbol_reader::install () m_objfile->per_bfd->minimal_symbol_count = mcount; m_objfile->per_bfd->msymbols = std::move (msym_holder); -#if CXX_STD_THREAD /* Mutex that is used when modifying or accessing the demangled hash table. */ - std::mutex demangled_mutex; -#endif + gdb::mutex demangled_mutex; std::vector hash_values (mcount); @@ -1562,11 +1548,8 @@ minimal_symbol_reader::install () gdb::parallel_for_each<1000, minimal_symbol *, minimal_symbol_install_worker> (&msymbols[0], &msymbols[mcount], msymbols, gdb::array_view (hash_values), - m_objfile->per_bfd -#if CXX_STD_THREAD - , demangled_mutex -#endif - ); + m_objfile->per_bfd, + demangled_mutex); build_minimal_symbol_hash_tables (m_objfile, hash_values); } diff --git a/gdb/run-on-main-thread.c b/gdb/run-on-main-thread.c index 0cfe4716c24739f4de3daacff555e546ea2e5925..d68811bebddcd8522c812930e8eec2efc3c462fe 100644 --- a/gdb/run-on-main-thread.c +++ b/gdb/run-on-main-thread.c @@ -18,11 +18,8 @@ #include "run-on-main-thread.h" #include "ser-event.h" -#if CXX_STD_THREAD -#include -#include -#endif #include "gdbsupport/cleanups.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/event-loop.h" /* The serial event used when posting runnables. */ @@ -33,17 +30,13 @@ static struct serial_event *runnable_event; static std::vector> runnables; -#if CXX_STD_THREAD - /* Mutex to hold when handling RUNNABLE_EVENT or RUNNABLES. */ -static std::mutex runnable_mutex; +static gdb::mutex runnable_mutex; /* The main thread's thread id. */ -static std::thread::id main_thread_id; - -#endif +static gdb::thread::id main_thread_id; /* Run all the queued runnables. */ @@ -55,9 +48,7 @@ run_events (int error, gdb_client_data client_data) /* Hold the lock while changing the globals, but not while running the runnables. */ { -#if CXX_STD_THREAD - std::lock_guard lock (runnable_mutex); -#endif + gdb::lock_guard lock (runnable_mutex); /* Clear the event fd. Do this before flushing the events list, so that any new event post afterwards is sure to re-awaken the @@ -100,47 +91,38 @@ run_events (int error, gdb_client_data client_data) void run_on_main_thread (std::function &&func) { -#if CXX_STD_THREAD - std::lock_guard lock (runnable_mutex); -#endif + gdb::lock_guard lock (runnable_mutex); runnables.emplace_back (std::move (func)); serial_event_set (runnable_event); } -#if CXX_STD_THREAD static bool main_thread_id_initialized = false; -#endif /* See run-on-main-thread.h. */ bool is_main_thread () { -#if CXX_STD_THREAD /* Initialize main_thread_id on first use of is_main_thread. */ if (!main_thread_id_initialized) { main_thread_id_initialized = true; - main_thread_id = std::this_thread::get_id (); + main_thread_id = gdb::this_thread::get_id (); } - return std::this_thread::get_id () == main_thread_id; -#else - return true; -#endif + return gdb::this_thread::get_id () == main_thread_id; } INIT_GDB_FILE (run_on_main_thread) { -#if CXX_STD_THREAD /* The variable main_thread_id should be initialized when entering main, or at an earlier use, so it should already be initialized here. */ gdb_assert (main_thread_id_initialized); /* Assume that we execute this in the main thread. */ gdb_assert (is_main_thread ()); -#endif + runnable_event = make_serial_event (); add_file_handler (serial_event_fd (runnable_event), run_events, nullptr, "run-on-main-thread"); @@ -150,9 +132,7 @@ INIT_GDB_FILE (run_on_main_thread) languages are shut down. */ add_final_cleanup ([] () { -#if CXX_STD_THREAD - std::lock_guard lock (runnable_mutex); -#endif + gdb::lock_guard lock (runnable_mutex); runnables.clear (); }); } diff --git a/gdbsupport/cxx-thread.h b/gdbsupport/cxx-thread.h new file mode 100644 index 0000000000000000000000000000000000000000..e4061ebef9dfbc4287c258ac4c4754a3a41cf410 --- /dev/null +++ b/gdbsupport/cxx-thread.h @@ -0,0 +1,243 @@ +/* Wrappers for C++ threading + + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef GDBSUPPORT_CXX_THREAD_H +#define GDBSUPPORT_CXX_THREAD_H + +/* This header implements shims for the parts of the C++ threading + library that are needed by gdb. + + The reason this exists is that some versions of libstdc++ do not + supply a working C++ thread implementation. In particular this was + true for several versions of the Windows compiler. See + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687. + + For systems where this works, this header just supplies aliases of + the standard functionality, in the "gdb" namespace. For example, + "gdb::mutex" is an alias for "std::mutex". + + For non-working ports, shims are provided. These are just the + subset needed by gdb, and they generally do nothing, or as little + as possible. In particular they all simply assume single-threaded + operation. */ + +#if CXX_STD_THREAD + +#include +#include +#include +#include + +namespace gdb +{ + +using condition_variable = std::condition_variable; +using cv_status = std::cv_status; +using future_status = std::future_status; +using mutex = std::mutex; +using recursive_mutex = std::recursive_mutex; +using thread = std::thread; + +namespace this_thread = std::this_thread; + +template +using lock_guard = std::lock_guard; + +template +using unique_lock = std::unique_lock; + +template +using future = std::future; + +} /* namespace gdb*/ + +#else + +#include + +namespace gdb +{ + +/* A do-nothing replacement for std::mutex. */ +struct mutex +{ + mutex () = default; + + DISABLE_COPY_AND_ASSIGN (mutex); + + void lock () + { + } + + void unlock () + { + } +}; + +/* A do-nothing replacement for std::recursive_mutex. */ +struct recursive_mutex +{ + recursive_mutex () = default; + + DISABLE_COPY_AND_ASSIGN (recursive_mutex); + + void lock () + { + } + + void unlock () + { + } +}; + +/* A do-nothing replacement for std::lock_guard. */ +template +struct lock_guard +{ + explicit lock_guard (T &m) + { + } + + DISABLE_COPY_AND_ASSIGN (lock_guard); +}; + +/* A do-nothing replacement for std::unique_lock. */ +template +struct unique_lock +{ + explicit unique_lock (T &m) + { + } + + DISABLE_COPY_AND_ASSIGN (unique_lock); +}; + +/* A compatibility enum for std::cv_status. */ +enum class cv_status +{ + no_timeout, + timeout, +}; + +/* A do-nothing replacement for std::condition_variable. */ +struct condition_variable +{ + condition_variable () = default; + + DISABLE_COPY_AND_ASSIGN (condition_variable); + + void notify_one () noexcept + { + } + + void wait (unique_lock &lock) + { + } + + template + cv_status wait_for (unique_lock &lock, + const std::chrono::duration &rel_time) + { + return cv_status::no_timeout; + } +}; + +/* A compatibility enum for std::future_status. This is just the + subset needed by gdb. */ +enum class future_status +{ + ready, + timeout, +}; + +/* A compatibility implementation of std::future. */ +template +class future +{ +public: + + explicit future (T value) + : m_value (std::move (value)) + { + } + + future () = default; + future (future &&other) = default; + future (const future &other) = delete; + future &operator= (future &&other) = default; + future &operator= (const future &other) = delete; + + void wait () const { } + + template + future_status wait_for (const std::chrono::duration &duration) + const + { + return future_status::ready; + } + + T get () { return std::move (m_value); } + +private: + + T m_value; +}; + +/* A specialization for void. */ + +template<> +class future +{ +public: + void wait () const { } + + template + future_status wait_for (const std::chrono::duration &duration) + const + { + return future_status::ready; + } + + void get () { } +}; + +/* Rather than try to write a gdb::thread class, we just use a + namespace since only the 'id' type is needed. Code manipulating + actual std::thread objects has to be wrapped in a check anyway. */ +namespace thread +{ +/* Replacement for std::thread::id. */ +using id = int; +} + +/* Replacement for std::this_thread. */ +namespace this_thread +{ +static inline thread::id +get_id () +{ + return 0; +} +} + +} /* namespace gdb */ + +#endif /* CXX_STD_THREAD */ + +#endif /* GDBSUPPORT_CXX_THREAD_H */ diff --git a/gdbsupport/thread-pool.h b/gdbsupport/thread-pool.h index f3ac94bf5882cb4233a5d4857449e41f48b9125f..b5b2934b8c3f8b56fbbe766b556a0ba808186a6c 100644 --- a/gdbsupport/thread-pool.h +++ b/gdbsupport/thread-pool.h @@ -24,99 +24,12 @@ #include #include #include -#if CXX_STD_THREAD -#include -#include -#include -#include -#endif #include -namespace gdb -{ - -#if CXX_STD_THREAD - -/* Simply use the standard future. */ -template -using future = std::future; - -/* ... and the standard future_status. */ -using future_status = std::future_status; - -#else /* CXX_STD_THREAD */ - -/* A compatibility enum for std::future_status. This is just the - subset needed by gdb. */ -enum class future_status -{ - ready, - timeout, -}; - -/* A compatibility wrapper for std::future. Once and - are available in all GCC builds -- should that ever happen - -- this can be removed. GCC does not implement threading for - MinGW, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687. - - Meanwhile, in this mode, there are no threads. Tasks submitted to - the thread pool are invoked immediately and their result is stored - here. The base template here simply wraps a T and provides some - std::future compatibility methods. The provided methods are chosen - based on what GDB needs presently. */ - -template -class future -{ -public: - - explicit future (T value) - : m_value (std::move (value)) - { - } - - future () = default; - future (future &&other) = default; - future (const future &other) = delete; - future &operator= (future &&other) = default; - future &operator= (const future &other) = delete; +#include "gdbsupport/cxx-thread.h" - void wait () const { } - - template - future_status wait_for (const std::chrono::duration &duration) - const - { - return future_status::ready; - } - - T get () { return std::move (m_value); } - -private: - - T m_value; -}; - -/* A specialization for void. */ - -template<> -class future +namespace gdb { -public: - void wait () const { } - - template - future_status wait_for (const std::chrono::duration &duration) - const - { - return future_status::ready; - } - - void get () { } -}; - -#endif /* CXX_STD_THREAD */ - /* A thread pool. -- 2.51.0