1 // Copyright 2019 Google LLC 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 // http://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 #include "fcp/tracing/tracing_recorder_impl.h" 16 17 #include <memory> 18 19 #include "absl/synchronization/mutex.h" 20 #include "fcp/base/monitoring.h" 21 #include "fcp/tracing/text_tracing_recorder_impl.h" 22 23 namespace fcp::tracing_internal { 24 25 class TracingState { 26 absl::Mutex mutex_; 27 bool using_thread_local_state_ = false; 28 TracingRecorderImpl* global_tracing_recorder_ = nullptr; 29 30 struct ThreadLocalState { 31 TracingRecorderImpl* tracing_recorder = nullptr; 32 // Ref count is used to track the number of times the same 33 // TracingRecorderImpl has been set in case of re-entrancy. 34 int ref_count = 0; 35 }; 36 GetThreadLocalState()37 static ThreadLocalState& GetThreadLocalState() { 38 thread_local static ThreadLocalState instance; 39 return instance; 40 } 41 GetOrCreateDefaultRecorder()42 static std::shared_ptr<TracingRecorderImpl> GetOrCreateDefaultRecorder() { 43 static auto lazy_init_instance = 44 new std::shared_ptr<TextTracingRecorderImpl>( 45 new TextTracingRecorderImpl(absl::LocalTimeZone())); 46 return *lazy_init_instance; 47 } 48 49 public: GetRecorderImpl()50 std::shared_ptr<TracingRecorderImpl> GetRecorderImpl() { 51 absl::ReaderMutexLock lock(&mutex_); 52 TracingRecorderImpl* tracing_recorder = 53 using_thread_local_state_ ? GetThreadLocalState().tracing_recorder 54 : global_tracing_recorder_; 55 return tracing_recorder ? tracing_recorder->shared_from_this() 56 : GetOrCreateDefaultRecorder(); 57 } 58 SetGlobalRecorderImpl(TracingRecorderImpl * impl)59 void SetGlobalRecorderImpl(TracingRecorderImpl* impl) { 60 absl::WriterMutexLock lock(&mutex_); 61 FCP_CHECK(!using_thread_local_state_) 62 << "Global and thread local tracing recorders can't be used at the " 63 "same time"; 64 FCP_CHECK(global_tracing_recorder_ == nullptr || impl == nullptr) 65 << "Only one global tracing recorder instance is supported"; 66 FCP_LOG(INFO) << "Setting global"; 67 global_tracing_recorder_ = impl; 68 } 69 SetThreadLocalRecorderImpl(TracingRecorderImpl * impl)70 void SetThreadLocalRecorderImpl(TracingRecorderImpl* impl) { 71 FCP_CHECK(impl != nullptr); 72 absl::WriterMutexLock lock(&mutex_); 73 auto& thread_local_state = GetThreadLocalState(); 74 FCP_CHECK(global_tracing_recorder_ == nullptr) 75 << "Global and thread local tracing recorders can't be used at the " 76 "same time"; 77 FCP_CHECK(thread_local_state.tracing_recorder == nullptr || 78 thread_local_state.tracing_recorder == impl) 79 << "Only one tracing recorder instance per thread is supported"; 80 thread_local_state.tracing_recorder = impl; 81 thread_local_state.ref_count++; 82 using_thread_local_state_ = true; 83 } 84 ResetThreadLocalRecorderImpl(TracingRecorderImpl * impl)85 void ResetThreadLocalRecorderImpl(TracingRecorderImpl* impl) { 86 FCP_CHECK(impl != nullptr); 87 absl::WriterMutexLock lock(&mutex_); 88 auto& thread_local_state = GetThreadLocalState(); 89 FCP_CHECK(thread_local_state.tracing_recorder == impl && 90 thread_local_state.ref_count > 0) 91 << "Attempting to uninstall thread local tracing recorder that isn't " 92 "currently installed"; 93 if (--thread_local_state.ref_count == 0) { 94 thread_local_state.tracing_recorder = nullptr; 95 } 96 } 97 EnsureNotSet(TracingRecorderImpl * impl)98 void EnsureNotSet(TracingRecorderImpl* impl) { 99 absl::WriterMutexLock lock(&mutex_); 100 FCP_CHECK(global_tracing_recorder_ != impl) 101 << "Trace recorder must not be set as global at destruction time"; 102 if (using_thread_local_state_) { 103 FCP_CHECK(GetThreadLocalState().tracing_recorder != impl) 104 << "Trace recorder must not be set as thread local at destruction " 105 "time"; 106 } 107 } 108 GetInstance()109 static TracingState& GetInstance() { 110 static TracingState* instance = new TracingState(); 111 return *instance; 112 } 113 }; 114 GetCurrent()115std::shared_ptr<TracingRecorderImpl> TracingRecorderImpl::GetCurrent() { 116 return TracingState::GetInstance().GetRecorderImpl(); 117 } 118 InstallAsGlobal()119void TracingRecorderImpl::InstallAsGlobal() { 120 FCP_CHECK(!is_global_); 121 TracingState::GetInstance().SetGlobalRecorderImpl(this); 122 is_global_ = true; 123 } 124 UninstallAsGlobal()125void TracingRecorderImpl::UninstallAsGlobal() { 126 FCP_CHECK(is_global_); 127 TracingState::GetInstance().SetGlobalRecorderImpl(nullptr); 128 is_global_ = false; 129 } 130 InstallAsThreadLocal()131void TracingRecorderImpl::InstallAsThreadLocal() { 132 TracingState::GetInstance().SetThreadLocalRecorderImpl(this); 133 } 134 UninstallAsThreadLocal()135void TracingRecorderImpl::UninstallAsThreadLocal() { 136 TracingState::GetInstance().ResetThreadLocalRecorderImpl(this); 137 } 138 ~TracingRecorderImpl()139TracingRecorderImpl::~TracingRecorderImpl() { 140 if (is_global_) { 141 UninstallAsGlobal(); 142 } 143 TracingState::GetInstance().EnsureNotSet(this); 144 } 145 146 } // namespace fcp::tracing_internal 147