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

Reply via email to