1616#include < atomic>
1717
1818#include " absl/base/internal/raw_logging.h" // For ABSL_RAW_CHECK
19- #include " absl/base/internal/spinlock .h"
19+ #include " absl/synchronization/mutex .h"
2020
2121namespace absl {
2222ABSL_NAMESPACE_BEGIN
2323namespace cord_internal {
2424
25- using ::absl::base_internal::SpinLockHolder;
25+ namespace {
2626
27- ABSL_CONST_INIT CordzHandle::Queue CordzHandle::global_queue_ (absl::kConstInit );
27+ struct Queue {
28+ Queue () = default ;
29+
30+ absl::Mutex mutex;
31+ std::atomic<CordzHandle*> dq_tail ABSL_GUARDED_BY (mutex){nullptr };
32+
33+ // Returns true if this delete queue is empty. This method does not acquire
34+ // the lock, but does a 'load acquire' observation on the delete queue tail.
35+ // It is used inside Delete() to check for the presence of a delete queue
36+ // without holding the lock. The assumption is that the caller is in the
37+ // state of 'being deleted', and can not be newly discovered by a concurrent
38+ // 'being constructed' snapshot instance. Practically, this means that any
39+ // such discovery (`find`, 'first' or 'next', etc) must have proper 'happens
40+ // before / after' semantics and atomic fences.
41+ bool IsEmpty () const ABSL_NO_THREAD_SAFETY_ANALYSIS {
42+ return dq_tail.load (std::memory_order_acquire) == nullptr ;
43+ }
44+ };
45+
46+ static Queue* GlobalQueue () {
47+ static Queue* global_queue = new Queue;
48+ return global_queue;
49+ }
50+
51+ } // namespace
2852
2953CordzHandle::CordzHandle (bool is_snapshot) : is_snapshot_(is_snapshot) {
54+ Queue* global_queue = GlobalQueue ();
3055 if (is_snapshot) {
31- SpinLockHolder lock (&queue_->mutex );
32- CordzHandle* dq_tail = queue_->dq_tail .load (std::memory_order_acquire);
56+ MutexLock lock (&global_queue->mutex );
57+ CordzHandle* dq_tail =
58+ global_queue->dq_tail .load (std::memory_order_acquire);
3359 if (dq_tail != nullptr ) {
3460 dq_prev_ = dq_tail;
3561 dq_tail->dq_next_ = this ;
3662 }
37- queue_ ->dq_tail .store (this , std::memory_order_release);
63+ global_queue ->dq_tail .store (this , std::memory_order_release);
3864 }
3965}
4066
4167CordzHandle::~CordzHandle () {
42- ODRCheck ();
68+ Queue* global_queue = GlobalQueue ();
4369 if (is_snapshot_) {
4470 std::vector<CordzHandle*> to_delete;
4571 {
46- SpinLockHolder lock (&queue_ ->mutex );
72+ MutexLock lock (&global_queue ->mutex );
4773 CordzHandle* next = dq_next_;
4874 if (dq_prev_ == nullptr ) {
4975 // We were head of the queue, delete every CordzHandle until we reach
@@ -59,7 +85,7 @@ CordzHandle::~CordzHandle() {
5985 if (next) {
6086 next->dq_prev_ = dq_prev_;
6187 } else {
62- queue_ ->dq_tail .store (dq_prev_, std::memory_order_release);
88+ global_queue ->dq_tail .store (dq_prev_, std::memory_order_release);
6389 }
6490 }
6591 for (CordzHandle* handle : to_delete) {
@@ -69,16 +95,15 @@ CordzHandle::~CordzHandle() {
6995}
7096
7197bool CordzHandle::SafeToDelete () const {
72- return is_snapshot_ || queue_ ->IsEmpty ();
98+ return is_snapshot_ || GlobalQueue () ->IsEmpty ();
7399}
74100
75101void CordzHandle::Delete (CordzHandle* handle) {
76102 assert (handle);
77103 if (handle) {
78- handle->ODRCheck ();
79- Queue* const queue = handle->queue_ ;
104+ Queue* const queue = GlobalQueue ();
80105 if (!handle->SafeToDelete ()) {
81- SpinLockHolder lock (&queue->mutex );
106+ MutexLock lock (&queue->mutex );
82107 CordzHandle* dq_tail = queue->dq_tail .load (std::memory_order_acquire);
83108 if (dq_tail != nullptr ) {
84109 handle->dq_prev_ = dq_tail;
@@ -93,8 +118,9 @@ void CordzHandle::Delete(CordzHandle* handle) {
93118
94119std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetDeleteQueue () {
95120 std::vector<const CordzHandle*> handles;
96- SpinLockHolder lock (&global_queue_.mutex );
97- CordzHandle* dq_tail = global_queue_.dq_tail .load (std::memory_order_acquire);
121+ Queue* global_queue = GlobalQueue ();
122+ MutexLock lock (&global_queue->mutex );
123+ CordzHandle* dq_tail = global_queue->dq_tail .load (std::memory_order_acquire);
98124 for (const CordzHandle* p = dq_tail; p; p = p->dq_prev_ ) {
99125 handles.push_back (p);
100126 }
@@ -103,13 +129,13 @@ std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetDeleteQueue() {
103129
104130bool CordzHandle::DiagnosticsHandleIsSafeToInspect (
105131 const CordzHandle* handle) const {
106- ODRCheck ();
107132 if (!is_snapshot_) return false ;
108133 if (handle == nullptr ) return true ;
109134 if (handle->is_snapshot_ ) return false ;
110135 bool snapshot_found = false ;
111- SpinLockHolder lock (&queue_->mutex );
112- for (const CordzHandle* p = queue_->dq_tail ; p; p = p->dq_prev_ ) {
136+ Queue* global_queue = GlobalQueue ();
137+ MutexLock lock (&global_queue->mutex );
138+ for (const CordzHandle* p = global_queue->dq_tail ; p; p = p->dq_prev_ ) {
113139 if (p == handle) return !snapshot_found;
114140 if (p == this ) snapshot_found = true ;
115141 }
@@ -119,13 +145,13 @@ bool CordzHandle::DiagnosticsHandleIsSafeToInspect(
119145
120146std::vector<const CordzHandle*>
121147CordzHandle::DiagnosticsGetSafeToInspectDeletedHandles () {
122- ODRCheck ();
123148 std::vector<const CordzHandle*> handles;
124149 if (!is_snapshot ()) {
125150 return handles;
126151 }
127152
128- SpinLockHolder lock (&queue_->mutex );
153+ Queue* global_queue = GlobalQueue ();
154+ MutexLock lock (&global_queue->mutex );
129155 for (const CordzHandle* p = dq_next_; p != nullptr ; p = p->dq_next_ ) {
130156 if (!p->is_snapshot ()) {
131157 handles.push_back (p);
0 commit comments