22#include <unordered_set>
40 hp.store(
nullptr, std::memory_order_relaxed);
42 next.store(
nullptr, std::memory_order_relaxed);
43 active.store(
false, std::memory_order_relaxed);
54 void protect(
void* p,
size_t slot = 0) noexcept {
66 void clear(
size_t slot = 0) noexcept {
78 [[nodiscard]]
bool contains(
void* p)
const noexcept {
80 if (hp.load(std::memory_order_acquire) == p) {
92 [[nodiscard]]
void*
get(
size_t slot = 0) const noexcept {
98 std::atomic<safe_hazard_pointer_record*>
next{
nullptr};
135 while (p !=
nullptr) {
136 bool expected =
false;
137 if (p->
active.compare_exchange_strong(
139 std::memory_order_acq_rel,
140 std::memory_order_relaxed)) {
148 p = p->
next.load(std::memory_order_acquire);
153 new_record->active.store(
true, std::memory_order_relaxed);
158 old_head =
head_.load(std::memory_order_relaxed);
159 new_record->
next.store(old_head, std::memory_order_relaxed);
160 }
while (!
head_.compare_exchange_weak(
161 old_head, new_record,
162 std::memory_order_release,
163 std::memory_order_relaxed));
176 if (record ==
nullptr) {
182 record->active.store(
false, std::memory_order_release);
199 bool should_collect =
false;
208 [p](
const auto& entry) { return entry.first == p; });
220 should_collect = (
retired_count_.load(std::memory_order_relaxed) >= threshold);
224 if (should_collect) {
259 auto* p =
head_.load(std::memory_order_relaxed);
260 while (p !=
nullptr) {
261 auto* next = p->next.load(std::memory_order_relaxed);
268 if (deleter && ptr) {
291 std::unordered_set<void*> hazards;
292 hazards.reserve(
active_count_.load(std::memory_order_relaxed) *
296 while (p !=
nullptr) {
299 void* hp = p->
get(i);
304 p = p->
next.load(std::memory_order_acquire);
308 size_t reclaimed = 0;
311 if (hazards.find(it->first) == hazards.end()) {
313 if (it->second && it->first) {
314 it->second(it->first);
330 static constexpr size_t BASE_THRESHOLD = 64;
331 static constexpr size_t PER_THREAD_THRESHOLD = 16;
332 static constexpr size_t MAX_THRESHOLD = 512;
335 return std::min(MAX_THRESHOLD, BASE_THRESHOLD +
active * PER_THREAD_THRESHOLD);
338 std::atomic<safe_hazard_pointer_record*>
head_{
nullptr};
391 ,
slot_(other.slot_) {
392 other.record_ =
nullptr;
396 if (
this != &other) {
402 other.record_ =
nullptr;
429 [[nodiscard]]
void*
get() const noexcept {
436 [[nodiscard]]
explicit operator bool() const noexcept {
466 [](
void* ptr) {
delete static_cast<T*
>(ptr); }
~safe_hazard_guard()
Destructor - releases the record.
safe_hazard_guard(safe_hazard_guard &&other) noexcept
void * get() const noexcept
Get protected pointer.
void protect(void *p) noexcept
Protect a pointer.
void clear() noexcept
Clear protection.
safe_hazard_guard & operator=(const safe_hazard_guard &)=delete
safe_hazard_guard & operator=(safe_hazard_guard &&other) noexcept
safe_hazard_guard(void *p=nullptr, size_t slot=0)
Construct guard, optionally protecting a pointer.
safe_hazard_pointer_record * record_
safe_hazard_guard(const safe_hazard_guard &)=delete
Global Hazard Pointer Domain Manager.
size_t active_count() const noexcept
Get active thread count.
~safe_hazard_pointer_domain()
std::atomic< size_t > active_count_
std::atomic< safe_hazard_pointer_record * > head_
std::atomic< size_t > retired_count_
safe_hazard_pointer_domain(const safe_hazard_pointer_domain &)=delete
void collect()
Collect reclaimable objects.
static safe_hazard_pointer_domain & instance()
Get singleton instance.
void retire(void *p, retire_callback deleter)
Retire a pointer for later reclamation.
safe_hazard_pointer_domain()=default
size_t retired_count() const noexcept
Get current retired count.
safe_hazard_pointer_domain & operator=(const safe_hazard_pointer_domain &)=delete
std::vector< std::pair< void *, retire_callback > > retired_list_
void release(safe_hazard_pointer_record *record) noexcept
Release a hazard pointer record.
std::function< void(void *)> retire_callback
safe_hazard_pointer_record * acquire()
Acquire a hazard pointer record for current thread.
size_t get_adaptive_threshold() const noexcept
Get adaptive threshold based on active thread count.
void collect_internal()
Collect reclaimable objects (internal, lock held)
Thread-local hazard pointer record with explicit memory ordering.
std::atomic< bool > active
std::atomic< safe_hazard_pointer_record * > next
bool contains(void *p) const noexcept
Check if a pointer is protected by this record.
std::array< std::atomic< void * >, MAX_HAZARD_POINTERS > hazard_pointers_
void clear(size_t slot=0) noexcept
Clear hazard pointer protection.
void protect(void *p, size_t slot=0) noexcept
Protect a pointer from reclamation.
void * get(size_t slot=0) const noexcept
Get protected pointer at slot.
safe_hazard_pointer_record()
static constexpr size_t MAX_HAZARD_POINTERS
Typed hazard pointer domain.
typed_safe_hazard_domain()=default
static typed_safe_hazard_domain & instance()
Core threading foundation of the thread system library.
@ active
Worker is actively processing jobs.
void safe_retire_hazard(T *p)