This series implements std::hazard_pointer per P2530R3 (C++26 [32.11.3]) in libstdc++.
The work was previously announced as an RFC against the standalone prototype: https://gcc.gnu.org/pipermail/libstdc++/2026-June/066807.html ("[RFC] P2530R3 std::hazard_pointer prototype") with one round of review from Tomasz Kaminski (deque for the slot pool, std::find on vector<bool>). Both suggestions are folded into the implementation here. CC'ing Tomasz on the series as a courtesy. Series layout (3 patches): [1/3] libstdc++: Add infrastructure for std::hazard_pointer (C++26) <hazard_pointer> header, bits/hazard_ptr.h stub, version.def entry (gated on gthread + hosted), Makefile.am registration, plus 1.cc and version.cc smoke tests for the feature-test macro. [2/3] libstdc++: Implement std::hazard_pointer (P2530R3) Full implementation in bits/hazard_ptr.h. Highlights below. [3/3] libstdc++: Add tests for std::hazard_pointer 18 DejaGnu test files under 30_threads/hazard_pointer/: per-API functional tests, compile-time noexcept and type- constraint checks, concurrent and thread-exit coverage, plus negative compile tests for the _Protectable concept, public / non-virtual base requirements on retire(), and the [[nodiscard]] discards. Implementation highlights (patch 2/3): * process-global _Domain singleton; grow-on-demand slot pool with cache-line-padded slots (__GCC_DESTRUCTIVE_SIZE) to prevent false sharing between threads using adjacent slots * std::deque<_Slot> for the slot pool -- pointer stability across growth so live hazard_pointer handles can keep a raw _Slot* (Tomasz's RFC suggestion) * per-thread retire list lazily registered in a singly-linked list; unregistered on thread exit; protected survivors offloaded to a domain-level orphan list for later reclamation * _M_synchronize() uses collect-then-snapshot ordering so a writer publishing a hazard concurrently either has the hazard in the snapshot or sees the object still in the source list and retries. This side-steps a TSan false-positive in the more obvious snapshot-then-collect ordering -- the cross-atomic SC argument needed there is beyond TSan's vector-clock model. * seq_cst pair between reset_protection(T*) store and _M_synchronize acquire-load snapshot, per P2530R3 [32.11.3.4.3] paragraphs 7 and 3. Release + acquire is insufficient on weak-memory targets: the hazard store can sit in the store buffer while the snapshot's acquire-load reads null. * _Protectable concept enforces that T derives from hazard_pointer_obj_base; retire() static_asserts the derivation is public and non-virtual. Two deliberate omissions: * Contracts-based preconditions are not ported from the prototype. The current impl uses __glibcxx_assert. __cpp_contracts is set whenever contracts syntax is supported regardless of contract semantic (ignore / observe / enforce), so it cannot gate a retired_ flag the way the prototype does. Once libstdc++ exposes a stable "contracts actually evaluated" macro I will follow up with the contracts and the corresponding death tests. * Concurrent tests run unconditionally but are not yet wired through a TSan target_board. The prototype runs the same tests under -fsanitize=thread in CI; happy to add a parallel run under the libstdc++ tsan options if reviewers prefer. Prototype repository (single-header, namespace `proto`, full prior discussion): https://github.com/PaulXiCao/hazard_pointer_prototype The prototype CI runs the same test bodies that this series ports, across the matrix: * gcc-14 + clang-21, Debug and Release * GCC 16 trunk with -fcontracts (exercises the pre()/post() annotations not ported here) * MSVC on windows-latest * AddressSanitizer + UndefinedBehaviorSanitizer (clang-21) * ThreadSanitizer (clang-21) * clang-tidy-21, clang-format-21 All jobs green on the commit the libstdc++ port was rebased onto. Tested on x86_64-pc-linux-gnu (standalone libstdc++ build). Paul Xi Cao (3): libstdc++: Add infrastructure for std::hazard_pointer (C++26) libstdc++: Implement std::hazard_pointer (P2530R3) libstdc++: Add tests for std::hazard_pointer libstdc++-v3/include/Makefile.am | 2 + libstdc++-v3/include/Makefile.in | 2 + libstdc++-v3/include/bits/hazard_ptr.h | 566 ++++++++++++++++++ libstdc++-v3/include/bits/version.def | 10 + libstdc++-v3/include/bits/version.h | 10 + libstdc++-v3/include/std/hazard_pointer | 44 ++ .../testsuite/30_threads/hazard_pointer/1.cc | 28 + .../30_threads/hazard_pointer/concurrent.cc | 226 +++++++ .../30_threads/hazard_pointer/ctor.cc | 102 ++++ .../hazard_pointer/custom_deleter.cc | 126 ++++ .../30_threads/hazard_pointer/empty.cc | 105 ++++ .../hazard_pointer/make_hazard_pointer.cc | 84 +++ .../30_threads/hazard_pointer/move_assign.cc | 91 +++ .../hazard_pointer/nodiscard_neg.cc | 58 ++ .../30_threads/hazard_pointer/noexcept.cc | 56 ++ .../30_threads/hazard_pointer/protect.cc | 96 +++ .../30_threads/hazard_pointer/protect_neg.cc | 43 ++ .../hazard_pointer/reset_protection.cc | 116 ++++ .../30_threads/hazard_pointer/retire.cc | 119 ++++ .../30_threads/hazard_pointer/retire_neg.cc | 39 ++ .../hazard_pointer/retire_virtual_neg.cc | 40 ++ .../30_threads/hazard_pointer/swap.cc | 133 ++++ .../30_threads/hazard_pointer/thread_exit.cc | 98 +++ .../30_threads/hazard_pointer/try_protect.cc | 132 ++++ .../hazard_pointer/type_constraints.cc | 56 ++ .../30_threads/hazard_pointer/version.cc | 29 + 26 files changed, 2411 insertions(+) create mode 100644 libstdc++-v3/include/bits/hazard_ptr.h create mode 100644 libstdc++-v3/include/std/hazard_pointer create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/1.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/concurrent.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/ctor.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/custom_deleter.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/empty.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/make_hazard_pointer.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/move_assign.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/nodiscard_neg.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/noexcept.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/protect.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/protect_neg.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/reset_protection.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/retire.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_neg.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_virtual_neg.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/swap.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/thread_exit.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/try_protect.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/type_constraints.cc create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/version.cc -- 2.54.0
