• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()115 std::shared_ptr<TracingRecorderImpl> TracingRecorderImpl::GetCurrent() {
116   return TracingState::GetInstance().GetRecorderImpl();
117 }
118 
InstallAsGlobal()119 void TracingRecorderImpl::InstallAsGlobal() {
120   FCP_CHECK(!is_global_);
121   TracingState::GetInstance().SetGlobalRecorderImpl(this);
122   is_global_ = true;
123 }
124 
UninstallAsGlobal()125 void TracingRecorderImpl::UninstallAsGlobal() {
126   FCP_CHECK(is_global_);
127   TracingState::GetInstance().SetGlobalRecorderImpl(nullptr);
128   is_global_ = false;
129 }
130 
InstallAsThreadLocal()131 void TracingRecorderImpl::InstallAsThreadLocal() {
132   TracingState::GetInstance().SetThreadLocalRecorderImpl(this);
133 }
134 
UninstallAsThreadLocal()135 void TracingRecorderImpl::UninstallAsThreadLocal() {
136   TracingState::GetInstance().ResetThreadLocalRecorderImpl(this);
137 }
138 
~TracingRecorderImpl()139 TracingRecorderImpl::~TracingRecorderImpl() {
140   if (is_global_) {
141     UninstallAsGlobal();
142   }
143   TracingState::GetInstance().EnsureNotSet(this);
144 }
145 
146 }  // namespace fcp::tracing_internal
147