1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_TRACING_DATA_SOURCE_H_ 18 #define INCLUDE_PERFETTO_TRACING_DATA_SOURCE_H_ 19 20 // This header contains the key class (DataSource) that a producer app should 21 // override in order to create a custom data source that gets tracing Start/Stop 22 // notifications and emits tracing data. 23 24 #include <assert.h> 25 #include <stddef.h> 26 #include <stdint.h> 27 28 #include <array> 29 #include <atomic> 30 #include <functional> 31 #include <memory> 32 #include <mutex> 33 34 #include "perfetto/base/build_config.h" 35 #include "perfetto/base/compiler.h" 36 #include "perfetto/base/export.h" 37 #include "perfetto/protozero/message.h" 38 #include "perfetto/protozero/message_handle.h" 39 #include "perfetto/tracing/buffer_exhausted_policy.h" 40 #include "perfetto/tracing/core/forward_decls.h" 41 #include "perfetto/tracing/internal/basic_types.h" 42 #include "perfetto/tracing/internal/data_source_internal.h" 43 #include "perfetto/tracing/internal/tracing_muxer.h" 44 #include "perfetto/tracing/locked_handle.h" 45 #include "perfetto/tracing/trace_writer_base.h" 46 47 #include "protos/perfetto/trace/trace_packet.pbzero.h" 48 49 // PERFETTO_COMPONENT_EXPORT is used to mark symbols in Perfetto's headers 50 // (typically templates) that are defined by the user outside of Perfetto and 51 // should be made visible outside the current module. (e.g., in Chrome's 52 // component build). 53 #if !defined(PERFETTO_COMPONENT_EXPORT) 54 #define PERFETTO_COMPONENT_EXPORT 55 #endif 56 57 namespace perfetto { 58 namespace internal { 59 class TracingMuxerImpl; 60 class TrackEventCategoryRegistry; 61 template <typename, const internal::TrackEventCategoryRegistry*> 62 class TrackEventDataSource; 63 } // namespace internal 64 65 // Base class with the virtual methods to get start/stop notifications. 66 // Embedders are supposed to derive the templated version below, not this one. 67 class PERFETTO_EXPORT DataSourceBase { 68 public: 69 virtual ~DataSourceBase(); 70 71 // TODO(primiano): change the const& args below to be pointers instead. It 72 // makes it more awkward to handle output arguments and require mutable(s). 73 // This requires synchronizing a breaking API change for existing embedders. 74 75 // OnSetup() is invoked when tracing is configured. In most cases this happens 76 // just before starting the trace. In the case of deferred start (see 77 // deferred_start in trace_config.proto) start might happen later. 78 class SetupArgs { 79 public: 80 // This is valid only within the scope of the OnSetup() call and must not 81 // be retained. 82 const DataSourceConfig* config = nullptr; 83 84 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 85 uint32_t internal_instance_index = 0; 86 }; 87 virtual void OnSetup(const SetupArgs&); 88 89 class StartArgs { 90 public: 91 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 92 uint32_t internal_instance_index = 0; 93 }; 94 virtual void OnStart(const StartArgs&); 95 96 class StopArgs { 97 public: 98 virtual ~StopArgs(); 99 100 // HandleAsynchronously() can optionally be called to defer the tracing 101 // session stop and write tracing data just before stopping. 102 // This function returns a closure that must be invoked after the last 103 // trace events have been emitted. The returned closure can be called from 104 // any thread. The caller also needs to explicitly call TraceContext.Flush() 105 // from the last Trace() lambda invocation because no other implicit flushes 106 // will happen after the stop signal. 107 // When this function is called, the tracing service will defer the stop of 108 // the tracing session until the returned closure is invoked. 109 // However, the caller cannot hang onto this closure for too long. The 110 // tracing service will forcefully stop the tracing session without waiting 111 // for pending producers after TraceConfig.data_source_stop_timeout_ms 112 // (default: 5s, can be overridden by Consumers when starting a trace). 113 // If the closure is called after this timeout an error will be logged and 114 // the trace data emitted will not be present in the trace. No other 115 // functional side effects (e.g. crashes or corruptions) will happen. In 116 // other words, it is fine to accidentally hold onto this closure for too 117 // long but, if that happens, some tracing data will be lost. 118 virtual std::function<void()> HandleStopAsynchronously() const = 0; 119 120 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 121 uint32_t internal_instance_index = 0; 122 }; 123 virtual void OnStop(const StopArgs&); 124 }; 125 126 struct DefaultDataSourceTraits { 127 // |IncrementalStateType| can optionally be used store custom per-sequence 128 // incremental data (e.g., interning tables). It should have a Clear() method 129 // for when incremental state needs to be cleared. See 130 // TraceContext::GetIncrementalState(). 131 using IncrementalStateType = void; 132 // |TlsStateType| can optionally be used to store custom per-sequence 133 // session data, which is not reset when incremental state is cleared 134 // (e.g. configuration options). 135 using TlsStateType = void; 136 137 // Allows overriding what type of thread-local state configuration the data 138 // source uses. By default every data source gets independent thread-local 139 // state, which means every instance uses separate trace writers and 140 // incremental state even on the same thread. Some data sources (most notably 141 // the track event data source) want to share trace writers and incremental 142 // state on the same thread. GetDataSourceTLSDefaultDataSourceTraits143 static internal::DataSourceThreadLocalState* GetDataSourceTLS( 144 internal::DataSourceStaticState* static_state, 145 internal::TracingTLS* root_tls) { 146 auto* ds_tls = &root_tls->data_sources_tls[static_state->index]; 147 // The per-type TLS is either zero-initialized or must have been initialized 148 // for this specific data source type. 149 assert(!ds_tls->static_state || 150 ds_tls->static_state->index == static_state->index); 151 return ds_tls; 152 } 153 }; 154 155 // Templated base class meant to be derived by embedders to create a custom data 156 // source. DataSourceType must be the type of the derived class itself, e.g.: 157 // class MyDataSource : public DataSourceBase<MyDataSource> {...}. 158 // 159 // |DataSourceTraits| allows customizing the behavior of the data source. See 160 // |DefaultDataSourceTraits|. 161 template <typename DataSourceType, 162 typename DataSourceTraits = DefaultDataSourceTraits> 163 class DataSource : public DataSourceBase { 164 struct DefaultTracePointTraits; 165 166 public: 167 // The BufferExhaustedPolicy to use for TraceWriters of this DataSource. 168 // Override this in your DataSource class to change the default, which is to 169 // drop data on shared memory overruns. 170 constexpr static BufferExhaustedPolicy kBufferExhaustedPolicy = 171 BufferExhaustedPolicy::kDrop; 172 173 // Argument passed to the lambda function passed to Trace() (below). 174 class TraceContext { 175 public: 176 using TracePacketHandle = 177 ::protozero::MessageHandle<::perfetto::protos::pbzero::TracePacket>; 178 179 TraceContext(TraceContext&&) noexcept = default; ~TraceContext()180 ~TraceContext() { 181 // If the data source is being intercepted, flush the trace writer after 182 // each trace point to make sure the interceptor sees the data right away. 183 if (PERFETTO_UNLIKELY(tls_inst_->is_intercepted)) 184 Flush(); 185 } 186 NewTracePacket()187 TracePacketHandle NewTracePacket() { 188 return tls_inst_->trace_writer->NewTracePacket(); 189 } 190 191 // Forces a commit of the thread-local tracing data written so far to the 192 // service. This is almost never required (tracing data is periodically 193 // committed as trace pages are filled up) and has a non-negligible 194 // performance hit (requires an IPC + refresh of the current thread-local 195 // chunk). The only case when this should be used is when handling OnStop() 196 // asynchronously, to ensure sure that the data is committed before the 197 // Stop timeout expires. 198 // The TracePacketHandle obtained by the last NewTracePacket() call must be 199 // finalized before calling Flush() (either implicitly by going out of scope 200 // or by explicitly calling Finalize()). 201 // |cb| is an optional callback. When non-null it will request the 202 // service to ACK the flush and will be invoked on an internal thread after 203 // the service has acknowledged it. The callback might be NEVER INVOKED if 204 // the service crashes or the IPC connection is dropped. 205 void Flush(std::function<void()> cb = {}) { 206 tls_inst_->trace_writer->Flush(cb); 207 } 208 209 // Returns the number of bytes written on the current thread by the current 210 // data-source since its creation. 211 // This can be useful for splitting protos that might grow very large. written()212 uint64_t written() { return tls_inst_->trace_writer->written(); } 213 214 // Returns a RAII handle to access the data source instance, guaranteeing 215 // that it won't be deleted on another thread (because of trace stopping) 216 // while accessing it from within the Trace() lambda. 217 // The returned handle can be invalid (nullptr) if tracing is stopped 218 // immediately before calling this. The caller is supposed to check for its 219 // validity before using it. After checking, the handle is guaranteed to 220 // remain valid until the handle goes out of scope. GetDataSourceLocked()221 LockedHandle<DataSourceType> GetDataSourceLocked() const { 222 auto* internal_state = static_state_.TryGet(instance_index_); 223 if (!internal_state) 224 return LockedHandle<DataSourceType>(); 225 return LockedHandle<DataSourceType>( 226 &internal_state->lock, 227 static_cast<DataSourceType*>(internal_state->data_source.get())); 228 } 229 230 // Post-condition: returned ptr will be non-null. GetCustomTlsState()231 typename DataSourceTraits::TlsStateType* GetCustomTlsState() { 232 PERFETTO_DCHECK(tls_inst_->data_source_custom_tls); 233 return reinterpret_cast<typename DataSourceTraits::TlsStateType*>( 234 tls_inst_->data_source_custom_tls.get()); 235 } 236 GetIncrementalState()237 typename DataSourceTraits::IncrementalStateType* GetIncrementalState() { 238 // Recreate incremental state data if it has been reset by the service. 239 if (tls_inst_->incremental_state_generation != 240 static_state_.incremental_state_generation.load( 241 std::memory_order_relaxed)) { 242 tls_inst_->incremental_state.reset(); 243 CreateIncrementalState(tls_inst_); 244 } 245 return reinterpret_cast<typename DataSourceTraits::IncrementalStateType*>( 246 tls_inst_->incremental_state.get()); 247 } 248 249 private: 250 friend class DataSource; 251 template <typename, const internal::TrackEventCategoryRegistry*> 252 friend class internal::TrackEventDataSource; TraceContext(internal::DataSourceInstanceThreadLocalState * tls_inst,uint32_t instance_index)253 TraceContext(internal::DataSourceInstanceThreadLocalState* tls_inst, 254 uint32_t instance_index) 255 : tls_inst_(tls_inst), instance_index_(instance_index) {} 256 TraceContext(const TraceContext&) = delete; 257 TraceContext& operator=(const TraceContext&) = delete; 258 259 internal::DataSourceInstanceThreadLocalState* const tls_inst_; 260 uint32_t const instance_index_; 261 }; 262 263 // The main tracing method. Tracing code should call this passing a lambda as 264 // argument, with the following signature: void(TraceContext). 265 // The lambda will be called synchronously (i.e., always before Trace() 266 // returns) only if tracing is enabled and the data source has been enabled in 267 // the tracing config. 268 // The lambda can be called more than once per Trace() call, in the case of 269 // concurrent tracing sessions (or even if the data source is instantiated 270 // twice within the same trace config). 271 template <typename Lambda> Trace(Lambda tracing_fn)272 static void Trace(Lambda tracing_fn) { 273 CallIfEnabled<DefaultTracePointTraits>([&tracing_fn](uint32_t instances) { 274 TraceWithInstances<DefaultTracePointTraits>(instances, 275 std::move(tracing_fn)); 276 }); 277 } 278 279 // An efficient trace point guard for checking if this data source is active. 280 // |callback| is a function which will only be called if there are active 281 // instances. It is given an instance state parameter, which should be passed 282 // to TraceWithInstances() to actually record trace data. 283 template <typename Traits = DefaultTracePointTraits, typename Callback> 284 static void CallIfEnabled(Callback callback, 285 typename Traits::TracePointData trace_point_data = 286 {}) PERFETTO_ALWAYS_INLINE { 287 // |instances| is a per-class bitmap that tells: 288 // 1. If the data source is enabled at all. 289 // 2. The index of the slot within |static_state_| that holds the instance 290 // state. In turn this allows to map the data source to the tracing 291 // session and buffers. 292 // memory_order_relaxed is okay because: 293 // - |instances| is re-read with an acquire barrier below if this succeeds. 294 // - The code between this point and the acquire-load is based on static 295 // storage which has indefinite lifetime. 296 uint32_t instances = Traits::GetActiveInstances(trace_point_data) 297 ->load(std::memory_order_relaxed); 298 299 // This is the tracing fast-path. Bail out immediately if tracing is not 300 // enabled (or tracing is enabled but not for this data source). 301 if (PERFETTO_LIKELY(!instances)) 302 return; 303 callback(instances); 304 } 305 306 // The "lower half" of a trace point which actually performs tracing after 307 // this data source has been determined to be active. 308 // |instances| must be the instance state value retrieved through 309 // CallIfEnabled(). 310 // |tracing_fn| will be called to record trace data as in Trace(). 311 // 312 // |trace_point_data| is an optional parameter given to |Traits:: 313 // GetActiveInstances| to make it possible to use custom storage for 314 // the data source enabled state. This is, for example, used by TrackEvent to 315 // implement per-tracing category enabled states. 316 // 317 // TODO(primiano): all the stuff below should be outlined from the trace 318 // point. Or at least we should have some compile-time traits like 319 // kOptimizeBinarySize / kOptimizeTracingLatency. 320 template <typename Traits = DefaultTracePointTraits, typename Lambda> 321 static void TraceWithInstances( 322 uint32_t instances, 323 Lambda tracing_fn, 324 typename Traits::TracePointData trace_point_data = {}) { 325 PERFETTO_DCHECK(instances); 326 constexpr auto kMaxDataSourceInstances = internal::kMaxDataSourceInstances; 327 328 // See tracing_muxer.h for the structure of the TLS. 329 auto* tracing_impl = internal::TracingMuxer::Get(); 330 if (PERFETTO_UNLIKELY(!tls_state_)) 331 tls_state_ = GetOrCreateDataSourceTLS(&static_state_); 332 333 // Avoid re-entering the trace point recursively. 334 if (PERFETTO_UNLIKELY(tls_state_->root_tls->is_in_trace_point)) 335 return; 336 internal::ScopedReentrancyAnnotator scoped_annotator(*tls_state_->root_tls); 337 338 // TracingTLS::generation is a global monotonic counter that is incremented 339 // every time a tracing session is stopped. We use that as a signal to force 340 // a slow-path garbage collection of all the trace writers for the current 341 // thread and to destroy the ones that belong to tracing sessions that have 342 // ended. This is to avoid having too many TraceWriter instances alive, each 343 // holding onto one chunk of the shared memory buffer. 344 // Rationale why memory_order_relaxed should be fine: 345 // - The TraceWriter object that we use is always constructed and destructed 346 // on the current thread. There is no risk of accessing a half-initialized 347 // TraceWriter (which would be really bad). 348 // - In the worst case, in the case of a race on the generation check, we 349 // might end up using a TraceWriter for the same data source that belongs 350 // to a stopped session. This is not really wrong, as we don't give any 351 // guarantee on the global atomicity of the stop. In the worst case the 352 // service will reject the data commit if this arrives too late. 353 354 if (PERFETTO_UNLIKELY( 355 tls_state_->root_tls->generation != 356 tracing_impl->generation(std::memory_order_relaxed))) { 357 // Will update root_tls->generation. 358 tracing_impl->DestroyStoppedTraceWritersForCurrentThread(); 359 } 360 361 for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) { 362 internal::DataSourceState* instance_state = 363 static_state_.TryGetCached(instances, i); 364 if (!instance_state) 365 continue; 366 367 // Even if we passed the check above, the DataSourceInstance might be 368 // still destroyed concurrently while this code runs. The code below is 369 // designed to deal with such race, as follows: 370 // - We don't access the user-defined data source instance state. The only 371 // bits of state we use are |backend_id| and |buffer_id|. 372 // - Beyond those two integers, we access only the TraceWriter here. The 373 // TraceWriter is always safe because it lives on the TLS. 374 // - |instance_state| is backed by static storage, so the pointer is 375 // always valid, even after the data source instance is destroyed. 376 // - In the case of a race-on-destruction, we'll still see the latest 377 // backend_id and buffer_id and in the worst case keep trying writing 378 // into the tracing shared memory buffer after stopped. But this isn't 379 // really any worse than the case of the stop IPC being delayed by the 380 // kernel scheduler. The tracing service is robust against data commit 381 // attemps made after tracing is stopped. 382 // There is a theoretical race that would case the wrong behavior w.r.t 383 // writing data in the wrong buffer, but it's so rare that we ignore it: 384 // if the data source is stopped and started kMaxDataSourceInstances 385 // times (so that the same id is recycled) while we are in this function, 386 // we might end up reusing the old data source's backend_id and buffer_id 387 // for the new one, because we don't see the generation change past this 388 // point. But stopping and starting tracing (even once) takes so much 389 // handshaking to make this extremely unrealistic. 390 391 auto& tls_inst = tls_state_->per_instance[i]; 392 if (PERFETTO_UNLIKELY(!tls_inst.trace_writer)) { 393 // Here we need an acquire barrier, which matches the release-store made 394 // by TracingMuxerImpl::SetupDataSource(), to ensure that the backend_id 395 // and buffer_id are consistent. 396 instances = Traits::GetActiveInstances(trace_point_data) 397 ->load(std::memory_order_acquire); 398 instance_state = static_state_.TryGetCached(instances, i); 399 if (!instance_state || !instance_state->trace_lambda_enabled) 400 continue; 401 tls_inst.muxer_id_for_testing = instance_state->muxer_id_for_testing; 402 tls_inst.backend_id = instance_state->backend_id; 403 tls_inst.backend_connection_id = instance_state->backend_connection_id; 404 tls_inst.buffer_id = instance_state->buffer_id; 405 tls_inst.data_source_instance_id = 406 instance_state->data_source_instance_id; 407 tls_inst.is_intercepted = instance_state->interceptor_id != 0; 408 tls_inst.trace_writer = tracing_impl->CreateTraceWriter( 409 &static_state_, i, instance_state, 410 DataSourceType::kBufferExhaustedPolicy); 411 CreateIncrementalState(&tls_inst); 412 CreateDataSourceCustomTLS(TraceContext(&tls_inst, i)); 413 // Even in the case of out-of-IDs, SharedMemoryArbiterImpl returns a 414 // NullTraceWriter. The returned pointer should never be null. 415 assert(tls_inst.trace_writer); 416 } 417 418 tracing_fn(TraceContext(&tls_inst, i)); 419 } 420 } 421 422 // Registers the data source on all tracing backends, including ones that 423 // connect after the registration. Doing so enables the data source to receive 424 // Setup/Start/Stop notifications and makes the Trace() method work when 425 // tracing is enabled and the data source is selected. 426 // This must be called after Tracing::Initialize(). 427 // Can return false to signal failure if attemping to register more than 428 // kMaxDataSources (32) data sources types or if tracing hasn't been 429 // initialized. 430 // The optional |constructor_args| will be passed to the data source when it 431 // is constructed. 432 template <class... Args> Register(const DataSourceDescriptor & descriptor,const Args &...constructor_args)433 static bool Register(const DataSourceDescriptor& descriptor, 434 const Args&... constructor_args) { 435 // Silences -Wunused-variable warning in case the trace method is not used 436 // by the translation unit that declares the data source. 437 (void)static_state_; 438 (void)tls_state_; 439 440 auto factory = [constructor_args...]() { 441 return std::unique_ptr<DataSourceBase>( 442 new DataSourceType(constructor_args...)); 443 }; 444 auto* tracing_impl = internal::TracingMuxer::Get(); 445 return tracing_impl->RegisterDataSource(descriptor, factory, 446 &static_state_); 447 } 448 449 // Updates the data source descriptor. UpdateDescriptor(const DataSourceDescriptor & descriptor)450 static void UpdateDescriptor(const DataSourceDescriptor& descriptor) { 451 auto* tracing_impl = internal::TracingMuxer::Get(); 452 tracing_impl->UpdateDataSourceDescriptor(descriptor, &static_state_); 453 } 454 455 private: 456 // Traits for customizing the behavior of a specific trace point. 457 struct DefaultTracePointTraits { 458 // By default, every call to DataSource::Trace() will record trace events 459 // for every active instance of that data source. A single trace point can, 460 // however, use a custom set of enable flags for more fine grained control 461 // of when that trace point is active. 462 // 463 // DANGER: when doing this, the data source must use the appropriate memory 464 // fences when changing the state of the bitmap. 465 // 466 // |TraceWithInstances| may be optionally given an additional parameter for 467 // looking up the enable flags. That parameter is passed as |TracePointData| 468 // to |GetActiveInstances|. This is, for example, used by TrackEvent to 469 // implement per-category enabled states. 470 struct TracePointData {}; GetActiveInstancesDefaultTracePointTraits471 static constexpr std::atomic<uint32_t>* GetActiveInstances(TracePointData) { 472 return &static_state_.valid_instances; 473 } 474 }; 475 476 // Create the user provided incremental state in the given thread-local 477 // storage. Note: The second parameter here is used to specialize the case 478 // where there is no incremental state type. 479 template <typename T> CreateIncrementalStateImpl(internal::DataSourceInstanceThreadLocalState * tls_inst,const T *)480 static void CreateIncrementalStateImpl( 481 internal::DataSourceInstanceThreadLocalState* tls_inst, 482 const T*) { 483 PERFETTO_DCHECK(!tls_inst->incremental_state); 484 tls_inst->incremental_state_generation = 485 static_state_.incremental_state_generation.load( 486 std::memory_order_relaxed); 487 tls_inst->incremental_state = 488 internal::DataSourceInstanceThreadLocalState::ObjectWithDeleter( 489 reinterpret_cast<void*>(new T()), 490 [](void* p) { delete reinterpret_cast<T*>(p); }); 491 } 492 CreateIncrementalStateImpl(internal::DataSourceInstanceThreadLocalState *,const void *)493 static void CreateIncrementalStateImpl( 494 internal::DataSourceInstanceThreadLocalState*, 495 const void*) {} 496 CreateIncrementalState(internal::DataSourceInstanceThreadLocalState * tls_inst)497 static void CreateIncrementalState( 498 internal::DataSourceInstanceThreadLocalState* tls_inst) { 499 CreateIncrementalStateImpl( 500 tls_inst, 501 static_cast<typename DataSourceTraits::IncrementalStateType*>(nullptr)); 502 } 503 504 // Create the user provided custom tls state in the given TraceContext's 505 // thread-local storage. Note: The second parameter here is used to 506 // specialize the case where there is no incremental state type. 507 template <typename T> CreateDataSourceCustomTLSImpl(const TraceContext & trace_context,const T *)508 static void CreateDataSourceCustomTLSImpl(const TraceContext& trace_context, 509 const T*) { 510 PERFETTO_DCHECK(!trace_context.tls_inst_->data_source_custom_tls); 511 trace_context.tls_inst_->data_source_custom_tls = 512 internal::DataSourceInstanceThreadLocalState::ObjectWithDeleter( 513 reinterpret_cast<void*>(new T(trace_context)), 514 [](void* p) { delete reinterpret_cast<T*>(p); }); 515 } 516 CreateDataSourceCustomTLSImpl(const TraceContext &,const void *)517 static void CreateDataSourceCustomTLSImpl(const TraceContext&, const void*) {} 518 CreateDataSourceCustomTLS(const TraceContext & trace_context)519 static void CreateDataSourceCustomTLS(const TraceContext& trace_context) { 520 CreateDataSourceCustomTLSImpl( 521 trace_context, 522 static_cast<typename DataSourceTraits::TlsStateType*>(nullptr)); 523 } 524 525 // Note that the returned object is one per-thread per-data-source-type, NOT 526 // per data-source *instance*. GetOrCreateDataSourceTLS(internal::DataSourceStaticState * static_state)527 static internal::DataSourceThreadLocalState* GetOrCreateDataSourceTLS( 528 internal::DataSourceStaticState* static_state) { 529 #if PERFETTO_BUILDFLAG(PERFETTO_OS_IOS) 530 PERFETTO_FATAL("Data source TLS not supported on iOS, see b/158814068"); 531 #endif 532 auto* tracing_impl = internal::TracingMuxer::Get(); 533 internal::TracingTLS* root_tls = tracing_impl->GetOrCreateTracingTLS(); 534 internal::DataSourceThreadLocalState* ds_tls = 535 DataSourceTraits::GetDataSourceTLS(static_state, root_tls); 536 // We keep re-initializing as the initialization is idempotent and not worth 537 // the code for extra checks. 538 ds_tls->static_state = static_state; 539 assert(!ds_tls->root_tls || ds_tls->root_tls == root_tls); 540 ds_tls->root_tls = root_tls; 541 return ds_tls; 542 } 543 544 // Static state. Accessed by the static Trace() method fastpaths. 545 static internal::DataSourceStaticState static_state_; 546 547 // This TLS object is a cached raw pointer and has deliberately no destructor. 548 // The Platform implementation is supposed to create and manage the lifetime 549 // of the Platform::ThreadLocalObject and take care of destroying it. 550 // This is because non-POD thread_local variables have subtleties (global 551 // destructors) that we need to defer to the embedder. In chromium's platform 552 // implementation, for instance, the tls slot is implemented using 553 // chromium's base::ThreadLocalStorage. 554 static PERFETTO_THREAD_LOCAL internal::DataSourceThreadLocalState* tls_state_; 555 }; 556 557 // static 558 template <typename T, typename D> 559 internal::DataSourceStaticState DataSource<T, D>::static_state_; 560 // static 561 template <typename T, typename D> 562 PERFETTO_THREAD_LOCAL internal::DataSourceThreadLocalState* 563 DataSource<T, D>::tls_state_; 564 565 } // namespace perfetto 566 567 // If placed at the end of a macro declaration, eats the semicolon at the end of 568 // the macro invocation (e.g., "MACRO(...);") to avoid warnings about extra 569 // semicolons. 570 #define PERFETTO_INTERNAL_SWALLOW_SEMICOLON() \ 571 extern int perfetto_internal_unused 572 573 // This macro must be used once for each data source next to the data source's 574 // declaration. 575 #define PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(...) \ 576 template <> \ 577 PERFETTO_COMPONENT_EXPORT perfetto::internal::DataSourceStaticState \ 578 perfetto::DataSource<__VA_ARGS__>::static_state_ 579 580 // This macro must be used once for each data source in one source file to 581 // allocate static storage for the data source's static state. 582 // 583 // Note: if MSVC fails with a C2086 (redefinition) error here, use the 584 // permissive- flag to enable standards-compliant mode. See 585 // https://developercommunity.visualstudio.com/content/problem/319447/ 586 // explicit-specialization-of-static-data-member-inco.html. 587 #define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(...) \ 588 template <> \ 589 PERFETTO_COMPONENT_EXPORT perfetto::internal::DataSourceStaticState \ 590 perfetto::DataSource<__VA_ARGS__>::static_state_ {} 591 592 #endif // INCLUDE_PERFETTO_TRACING_DATA_SOURCE_H_ 593