summaryrefslogtreecommitdiff
path: root/absl/strings/internal/cordz_handle.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/internal/cordz_handle.h')
-rw-r--r--absl/strings/internal/cordz_handle.h97
1 files changed, 97 insertions, 0 deletions
diff --git a/absl/strings/internal/cordz_handle.h b/absl/strings/internal/cordz_handle.h
new file mode 100644
index 00000000..0235d4bd
--- /dev/null
+++ b/absl/strings/internal/cordz_handle.h
@@ -0,0 +1,97 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_CORDZ_HANDLE_H_
+#define ABSL_STRINGS_CORDZ_HANDLE_H_
+
+#include <atomic>
+#include <vector>
+
+#include "absl/base/config.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// This base class allows multiple types of object (CordzInfo and
+// CordzSampleToken) to exist simultaneously on the delete queue (pointed to by
+// global_dq_tail and traversed using dq_prev_ and dq_next_). The
+// delete queue guarantees that once a profiler creates a CordzSampleToken and
+// has gained visibility into a CordzInfo object, that CordzInfo object will not
+// be deleted prematurely. This allows the profiler to inspect all CordzInfo
+// objects that are alive without needing to hold a global lock.
+class CordzHandle {
+ public:
+ CordzHandle() : CordzHandle(false) {}
+
+ bool is_snapshot() const { return is_snapshot_; }
+
+ // Deletes the provided instance, or puts it on the delete queue to be deleted
+ // once there are no more sample tokens (snapshot) instances potentially
+ // referencing the instance. `handle` may be null.
+ static void Delete(CordzHandle* handle);
+
+ // Returns the current entries in the delete queue in LIFO order.
+ static std::vector<const CordzHandle*> DiagnosticsGetDeleteQueue();
+
+ // Returns true if the provided handle is nullptr or guarded by this handle.
+ // Since the CordzSnapshot token is itself a CordzHandle, this method will
+ // allow tests to check if that token is keeping an arbitrary CordzHandle
+ // alive.
+ bool DiagnosticsHandleIsSafeToInspect(const CordzHandle* handle) const;
+
+ // Returns the current entries in the delete queue, in LIFO order, that are
+ // protected by this. CordzHandle objects are only placed on the delete queue
+ // after CordzHandle::Delete is called with them as an argument. Only
+ // CordzHandle objects that are not also CordzSnapshot objects will be
+ // included in the return vector. For each of the handles in the return
+ // vector, the earliest that their memory can be freed is when this
+ // CordzSnapshot object is deleted.
+ std::vector<const CordzHandle*> DiagnosticsGetSafeToInspectDeletedHandles();
+
+ protected:
+ explicit CordzHandle(bool is_snapshot);
+ virtual ~CordzHandle();
+
+ private:
+ // Returns true if the 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.
+ static bool UnsafeDeleteQueueEmpty() ABSL_NO_THREAD_SAFETY_ANALYSIS {
+ return dq_tail_.load(std::memory_order_acquire) == nullptr;
+ }
+
+ const bool is_snapshot_;
+ static absl::Mutex mutex_;
+ static std::atomic<CordzHandle*> dq_tail_ ABSL_GUARDED_BY(mutex_);
+ CordzHandle* dq_prev_ ABSL_GUARDED_BY(mutex_) = nullptr;
+ CordzHandle* dq_next_ ABSL_GUARDED_BY(mutex_) = nullptr;
+};
+
+class CordzSnapshot : public CordzHandle {
+ public:
+ CordzSnapshot() : CordzHandle(true) {}
+};
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STRINGS_CORDZ_HANDLE_H_