Skip to content

Commit 511de5b

Browse files
martijnvelscopybara-github
authored andcommitted
Change Cordz to synchronize tracked cords with Snapshots / DeleteQueue
PiperOrigin-RevId: 817217091 Change-Id: I93ae36c50ec475daa765b53877b1e23bcee6fad6
1 parent 78c54a5 commit 511de5b

File tree

2 files changed

+21
-25
lines changed

2 files changed

+21
-25
lines changed

absl/strings/internal/cordz_info.cc

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include <cstdint>
1818

1919
#include "absl/base/config.h"
20-
#include "absl/base/internal/spinlock.h"
20+
#include "absl/base/const_init.h"
2121
#include "absl/container/inlined_vector.h"
2222
#include "absl/debugging/stacktrace.h"
2323
#include "absl/strings/internal/cord_internal.h"
@@ -224,21 +224,23 @@ class CordRepAnalyzer {
224224
CordzInfo* CordzInfo::Head(const CordzSnapshot& snapshot) {
225225
ABSL_ASSERT(snapshot.is_snapshot());
226226

227-
// We can do an 'unsafe' load of 'head', as we are guaranteed that the
228-
// instance it points to is kept alive by the provided CordzSnapshot, so we
229-
// can simply return the current value using an acquire load.
227+
// We obtain the lock here as we must synchronize the first call into the list
228+
// with any concurrent 'Untrack()` operation to avoid any read in the list to
229+
// reorder before the observation of the thread 'untracking a cord' of the
230+
// delete queue being empty or not. After this all next observations are safe
231+
// as we have established all subsequent untracks will be queued for delete.
230232
// We do enforce in DEBUG builds that the 'head' value is present in the
231233
// delete queue: ODR violations may lead to 'snapshot' and 'global_list_'
232234
// being in different libraries / modules.
233-
CordzInfo* head = global_list_.head.load(std::memory_order_acquire);
234-
ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(head));
235-
return head;
235+
absl::MutexLock l(global_list_.mutex);
236+
ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(global_list_.head));
237+
return global_list_.head;
236238
}
237239

238240
CordzInfo* CordzInfo::Next(const CordzSnapshot& snapshot) const {
239241
ABSL_ASSERT(snapshot.is_snapshot());
240242

241-
// Similar to the 'Head()' function, we do not need a mutex here.
243+
// We do not need a lock here. See also comments in Head().
242244
CordzInfo* next = ci_next_.load(std::memory_order_acquire);
243245
ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(this));
244246
ABSL_ASSERT(snapshot.DiagnosticsHandleIsSafeToInspect(next));
@@ -327,22 +329,21 @@ CordzInfo::~CordzInfo() {
327329
}
328330

329331
void CordzInfo::Track() {
330-
SpinLockHolder l(list_->mutex);
331-
332-
CordzInfo* const head = list_->head.load(std::memory_order_acquire);
332+
absl::MutexLock l(list_->mutex);
333+
CordzInfo* const head = list_->head;
333334
if (head != nullptr) {
334335
head->ci_prev_.store(this, std::memory_order_release);
335336
}
336337
ci_next_.store(head, std::memory_order_release);
337-
list_->head.store(this, std::memory_order_release);
338+
list_->head = this;
338339
}
339340

340341
void CordzInfo::Untrack() {
341342
ODRCheck();
342343
{
343-
SpinLockHolder l(list_->mutex);
344+
absl::MutexLock l(list_->mutex);
344345

345-
CordzInfo* const head = list_->head.load(std::memory_order_acquire);
346+
CordzInfo* const head = list_->head;
346347
CordzInfo* const next = ci_next_.load(std::memory_order_acquire);
347348
CordzInfo* const prev = ci_prev_.load(std::memory_order_acquire);
348349

@@ -356,7 +357,7 @@ void CordzInfo::Untrack() {
356357
prev->ci_next_.store(next, std::memory_order_release);
357358
} else {
358359
ABSL_ASSERT(head == this);
359-
list_->head.store(next, std::memory_order_release);
360+
list_->head = next;
360361
}
361362
}
362363

absl/strings/internal/cordz_info.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
#include <functional>
2121

2222
#include "absl/base/config.h"
23+
#include "absl/base/const_init.h"
2324
#include "absl/base/internal/raw_logging.h"
24-
#include "absl/base/internal/spinlock.h"
2525
#include "absl/base/thread_annotations.h"
2626
#include "absl/strings/internal/cord_internal.h"
2727
#include "absl/strings/internal/cordz_functions.h"
@@ -121,12 +121,10 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
121121
CordzInfo& operator=(const CordzInfo&) = delete;
122122

123123
// Retrieves the oldest existing CordzInfo.
124-
static CordzInfo* Head(const CordzSnapshot& snapshot)
125-
ABSL_NO_THREAD_SAFETY_ANALYSIS;
124+
static CordzInfo* Head(const CordzSnapshot& snapshot);
126125

127126
// Retrieves the next oldest existing CordzInfo older than 'this' instance.
128-
CordzInfo* Next(const CordzSnapshot& snapshot) const
129-
ABSL_NO_THREAD_SAFETY_ANALYSIS;
127+
CordzInfo* Next(const CordzSnapshot& snapshot) const;
130128

131129
// Locks this instance for the update identified by `method`.
132130
// Increases the count for `method` in `update_tracker`.
@@ -185,16 +183,13 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
185183
int64_t sampling_stride() const { return sampling_stride_; }
186184

187185
private:
188-
using SpinLock = absl::base_internal::SpinLock;
189-
using SpinLockHolder = ::absl::base_internal::SpinLockHolder;
190-
191186
// Global cordz info list. CordzInfo stores a pointer to the global list
192187
// instance to harden against ODR violations.
193188
struct List {
194189
constexpr explicit List(absl::ConstInitType) {}
195190

196-
SpinLock mutex;
197-
std::atomic<CordzInfo*> head ABSL_GUARDED_BY(mutex){nullptr};
191+
absl::Mutex mutex{absl::kConstInit};
192+
CordzInfo* head ABSL_GUARDED_BY(mutex){nullptr};
198193
};
199194

200195
static constexpr size_t kMaxStackDepth = 64;

0 commit comments

Comments
 (0)