1 // Copyright 2019 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ 16 #define ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ 17 18 #include <atomic> 19 #include <vector> 20 21 #include "absl/base/config.h" 22 #include "absl/base/internal/raw_logging.h" 23 24 namespace absl { 25 ABSL_NAMESPACE_BEGIN 26 namespace cord_internal { 27 28 // This base class allows multiple types of object (CordzInfo and 29 // CordzSampleToken) to exist simultaneously on the delete queue (pointed to by 30 // global_dq_tail and traversed using dq_prev_ and dq_next_). The 31 // delete queue guarantees that once a profiler creates a CordzSampleToken and 32 // has gained visibility into a CordzInfo object, that CordzInfo object will not 33 // be deleted prematurely. This allows the profiler to inspect all CordzInfo 34 // objects that are alive without needing to hold a global lock. 35 class ABSL_DLL CordzHandle { 36 public: CordzHandle()37 CordzHandle() : CordzHandle(false) {} 38 is_snapshot()39 bool is_snapshot() const { return is_snapshot_; } 40 41 // Returns true if this instance is safe to be deleted because it is either a 42 // snapshot, which is always safe to delete, or not included in the global 43 // delete queue and thus not included in any snapshot. 44 // Callers are responsible for making sure this instance can not be newly 45 // discovered by other threads. For example, CordzInfo instances first de-list 46 // themselves from the global CordzInfo list before determining if they are 47 // safe to be deleted directly. 48 // If SafeToDelete returns false, callers MUST use the Delete() method to 49 // safely queue CordzHandle instances for deletion. 50 bool SafeToDelete() const; 51 52 // Deletes the provided instance, or puts it on the delete queue to be deleted 53 // once there are no more sample tokens (snapshot) instances potentially 54 // referencing the instance. `handle` should not be null. 55 static void Delete(CordzHandle* handle); 56 57 // Returns the current entries in the delete queue in LIFO order. 58 static std::vector<const CordzHandle*> DiagnosticsGetDeleteQueue(); 59 60 // Returns true if the provided handle is nullptr or guarded by this handle. 61 // Since the CordzSnapshot token is itself a CordzHandle, this method will 62 // allow tests to check if that token is keeping an arbitrary CordzHandle 63 // alive. 64 bool DiagnosticsHandleIsSafeToInspect(const CordzHandle* handle) const; 65 66 // Returns the current entries in the delete queue, in LIFO order, that are 67 // protected by this. CordzHandle objects are only placed on the delete queue 68 // after CordzHandle::Delete is called with them as an argument. Only 69 // CordzHandle objects that are not also CordzSnapshot objects will be 70 // included in the return vector. For each of the handles in the return 71 // vector, the earliest that their memory can be freed is when this 72 // CordzSnapshot object is deleted. 73 std::vector<const CordzHandle*> DiagnosticsGetSafeToInspectDeletedHandles(); 74 75 protected: 76 explicit CordzHandle(bool is_snapshot); 77 virtual ~CordzHandle(); 78 79 private: 80 const bool is_snapshot_; 81 82 // dq_prev_ and dq_next_ require the global queue mutex to be held. 83 // Unfortunately we can't use thread annotations such that the thread safety 84 // analysis understands that queue_ and global_queue_ are one and the same. 85 CordzHandle* dq_prev_ = nullptr; 86 CordzHandle* dq_next_ = nullptr; 87 }; 88 89 class CordzSnapshot : public CordzHandle { 90 public: CordzSnapshot()91 CordzSnapshot() : CordzHandle(true) {} 92 }; 93 94 } // namespace cord_internal 95 ABSL_NAMESPACE_END 96 } // namespace absl 97 98 #endif // ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ 99