diff options
author | Derek Mauro <dmauro@google.com> | 2023-05-12 08:45:48 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-05-12 08:46:58 -0700 |
commit | 3aa3377ef66e6388ed19fd7c862bf0dc3a3630e0 (patch) | |
tree | 6ab3adb03426b67da67f4e8ac679dec8a7e8a7dc /absl/strings/internal/cordz_handle.cc | |
parent | 2526926b9275076b03159e7e0a9f1f32b9ed8d09 (diff) |
Fixed Windows DLL builds of test targets
This is a heavily modified version of
https://github.com/abseil/abseil-cpp/pull/1445,
which adds some missing test libraries to the test DLL.
Unlike #1445, this change moves several global variables out of
headers that did not need to be in headers.
For instance, cord_btree_exhaustive_validation was a global
defined/declared in cord_internal, but only used in cord_rep_btree
and its test.
cordz_handle defined a queue in its header even though it wasn't needed,
which also led to ODR problems.
The Spinlock used in CordzHandle is replaced with a Mutex. This was
originally a Mutex, but Chromium asked us to change it to a Spinlock
to avoid a static initializer. After this change, the static
initializer is no longer an issue.
#1407
PiperOrigin-RevId: 531516991
Change-Id: I0e431a193698b20ba03fac6e414c26f153f330a7
Diffstat (limited to 'absl/strings/internal/cordz_handle.cc')
-rw-r--r-- | absl/strings/internal/cordz_handle.cc | 66 |
1 files changed, 46 insertions, 20 deletions
diff --git a/absl/strings/internal/cordz_handle.cc b/absl/strings/internal/cordz_handle.cc index a73fefed..a7061dbe 100644 --- a/absl/strings/internal/cordz_handle.cc +++ b/absl/strings/internal/cordz_handle.cc @@ -16,34 +16,60 @@ #include <atomic> #include "absl/base/internal/raw_logging.h" // For ABSL_RAW_CHECK -#include "absl/base/internal/spinlock.h" +#include "absl/synchronization/mutex.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { -using ::absl::base_internal::SpinLockHolder; +namespace { -ABSL_CONST_INIT CordzHandle::Queue CordzHandle::global_queue_(absl::kConstInit); +struct Queue { + Queue() = default; + + absl::Mutex mutex; + std::atomic<CordzHandle*> dq_tail ABSL_GUARDED_BY(mutex){nullptr}; + + // Returns true if this delete queue is empty. This method does not acquire + // the lock, but does a 'load acquire' observation on the delete queue tail. + // It is used inside Delete() to check for the presence of a delete queue + // without holding the lock. The assumption is that the caller is in the + // state of 'being deleted', and can not be newly discovered by a concurrent + // 'being constructed' snapshot instance. Practically, this means that any + // such discovery (`find`, 'first' or 'next', etc) must have proper 'happens + // before / after' semantics and atomic fences. + bool IsEmpty() const ABSL_NO_THREAD_SAFETY_ANALYSIS { + return dq_tail.load(std::memory_order_acquire) == nullptr; + } +}; + +static Queue* GlobalQueue() { + static Queue* global_queue = new Queue; + return global_queue; +} + +} // namespace CordzHandle::CordzHandle(bool is_snapshot) : is_snapshot_(is_snapshot) { + Queue* global_queue = GlobalQueue(); if (is_snapshot) { - SpinLockHolder lock(&queue_->mutex); - CordzHandle* dq_tail = queue_->dq_tail.load(std::memory_order_acquire); + MutexLock lock(&global_queue->mutex); + CordzHandle* dq_tail = + global_queue->dq_tail.load(std::memory_order_acquire); if (dq_tail != nullptr) { dq_prev_ = dq_tail; dq_tail->dq_next_ = this; } - queue_->dq_tail.store(this, std::memory_order_release); + global_queue->dq_tail.store(this, std::memory_order_release); } } CordzHandle::~CordzHandle() { - ODRCheck(); + Queue* global_queue = GlobalQueue(); if (is_snapshot_) { std::vector<CordzHandle*> to_delete; { - SpinLockHolder lock(&queue_->mutex); + MutexLock lock(&global_queue->mutex); CordzHandle* next = dq_next_; if (dq_prev_ == nullptr) { // We were head of the queue, delete every CordzHandle until we reach @@ -59,7 +85,7 @@ CordzHandle::~CordzHandle() { if (next) { next->dq_prev_ = dq_prev_; } else { - queue_->dq_tail.store(dq_prev_, std::memory_order_release); + global_queue->dq_tail.store(dq_prev_, std::memory_order_release); } } for (CordzHandle* handle : to_delete) { @@ -69,16 +95,15 @@ CordzHandle::~CordzHandle() { } bool CordzHandle::SafeToDelete() const { - return is_snapshot_ || queue_->IsEmpty(); + return is_snapshot_ || GlobalQueue()->IsEmpty(); } void CordzHandle::Delete(CordzHandle* handle) { assert(handle); if (handle) { - handle->ODRCheck(); - Queue* const queue = handle->queue_; + Queue* const queue = GlobalQueue(); if (!handle->SafeToDelete()) { - SpinLockHolder lock(&queue->mutex); + MutexLock lock(&queue->mutex); CordzHandle* dq_tail = queue->dq_tail.load(std::memory_order_acquire); if (dq_tail != nullptr) { handle->dq_prev_ = dq_tail; @@ -93,8 +118,9 @@ void CordzHandle::Delete(CordzHandle* handle) { std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetDeleteQueue() { std::vector<const CordzHandle*> handles; - SpinLockHolder lock(&global_queue_.mutex); - CordzHandle* dq_tail = global_queue_.dq_tail.load(std::memory_order_acquire); + Queue* global_queue = GlobalQueue(); + MutexLock lock(&global_queue->mutex); + CordzHandle* dq_tail = global_queue->dq_tail.load(std::memory_order_acquire); for (const CordzHandle* p = dq_tail; p; p = p->dq_prev_) { handles.push_back(p); } @@ -103,13 +129,13 @@ std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetDeleteQueue() { bool CordzHandle::DiagnosticsHandleIsSafeToInspect( const CordzHandle* handle) const { - ODRCheck(); if (!is_snapshot_) return false; if (handle == nullptr) return true; if (handle->is_snapshot_) return false; bool snapshot_found = false; - SpinLockHolder lock(&queue_->mutex); - for (const CordzHandle* p = queue_->dq_tail; p; p = p->dq_prev_) { + Queue* global_queue = GlobalQueue(); + MutexLock lock(&global_queue->mutex); + for (const CordzHandle* p = global_queue->dq_tail; p; p = p->dq_prev_) { if (p == handle) return !snapshot_found; if (p == this) snapshot_found = true; } @@ -119,13 +145,13 @@ bool CordzHandle::DiagnosticsHandleIsSafeToInspect( std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetSafeToInspectDeletedHandles() { - ODRCheck(); std::vector<const CordzHandle*> handles; if (!is_snapshot()) { return handles; } - SpinLockHolder lock(&queue_->mutex); + Queue* global_queue = GlobalQueue(); + MutexLock lock(&global_queue->mutex); for (const CordzHandle* p = dq_next_; p != nullptr; p = p->dq_next_) { if (!p->is_snapshot()) { handles.push_back(p); |