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/protozero/message_handle.h" 35 #include "perfetto/tracing/buffer_exhausted_policy.h" 36 #include "perfetto/tracing/core/flush_flags.h" 37 #include "perfetto/tracing/core/forward_decls.h" 38 #include "perfetto/tracing/internal/basic_types.h" 39 #include "perfetto/tracing/internal/data_source_internal.h" 40 #include "perfetto/tracing/internal/data_source_type.h" 41 #include "perfetto/tracing/internal/tracing_muxer.h" 42 #include "perfetto/tracing/locked_handle.h" 43 #include "perfetto/tracing/trace_writer_base.h" 44 45 #include "protos/perfetto/trace/trace_packet.pbzero.h" 46 47 // DEPRECATED: Instead of using this macro, prefer specifying symbol linkage 48 // attributes explicitly using the `_WITH_ATTRS` macro variants (e.g., 49 // PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS). This avoids 50 // potential macro definition collisions between two libraries using Perfetto. 51 // 52 // PERFETTO_COMPONENT_EXPORT is used to mark symbols in Perfetto's headers 53 // (typically templates) that are defined by the user outside of Perfetto and 54 // should be made visible outside the current module. (e.g., in Chrome's 55 // component build). 56 #if !defined(PERFETTO_COMPONENT_EXPORT) 57 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC) 58 // Workaround for C4003: not enough arguments for function-like macro invocation 59 // 'PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE' 60 #define PERFETTO_COMPONENT_EXPORT __declspec() 61 #else 62 #define PERFETTO_COMPONENT_EXPORT 63 #endif 64 #endif 65 66 namespace perfetto { 67 namespace internal { 68 class TracingMuxerImpl; 69 class TrackEventCategoryRegistry; 70 template <typename, const internal::TrackEventCategoryRegistry*> 71 class TrackEventDataSource; 72 } // namespace internal 73 74 namespace shlib { 75 class TrackEvent; 76 } // namespace shlib 77 78 namespace test { 79 class DataSourceInternalForTest; 80 } // namespace test 81 82 // Base class with the virtual methods to get start/stop notifications. 83 // Embedders are supposed to derive the templated version below, not this one. 84 class PERFETTO_EXPORT_COMPONENT DataSourceBase { 85 public: 86 virtual ~DataSourceBase(); 87 88 // TODO(primiano): change the const& args below to be pointers instead. It 89 // makes it more awkward to handle output arguments and require mutable(s). 90 // This requires synchronizing a breaking API change for existing embedders. 91 92 // OnSetup() is invoked when tracing is configured. In most cases this happens 93 // just before starting the trace. In the case of deferred start (see 94 // deferred_start in trace_config.proto) start might happen later. 95 // 96 // Can be called from any thread. 97 class SetupArgs { 98 public: 99 // This is valid only within the scope of the OnSetup() call and must not 100 // be retained. 101 const DataSourceConfig* config = nullptr; 102 103 // Backend type. 104 BackendType backend_type = kUnspecifiedBackend; 105 106 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 107 uint32_t internal_instance_index = 0; 108 }; 109 virtual void OnSetup(const SetupArgs&); 110 111 class StartArgs { 112 public: 113 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 114 uint32_t internal_instance_index = 0; 115 }; 116 // Invoked after tracing is actually started. 117 // 118 // Can be called from any thread. 119 virtual void OnStart(const StartArgs&); 120 121 class PERFETTO_EXPORT_COMPONENT StopArgs { 122 public: 123 virtual ~StopArgs(); 124 125 // HandleAsynchronously() can optionally be called to defer the tracing 126 // session stop and write tracing data just before stopping. 127 // This function returns a closure that must be invoked after the last 128 // trace events have been emitted. The returned closure can be called from 129 // any thread. The caller also needs to explicitly call TraceContext.Flush() 130 // from the last Trace() lambda invocation because no other implicit flushes 131 // will happen after the stop signal. 132 // When this function is called, the tracing service will defer the stop of 133 // the tracing session until the returned closure is invoked. 134 // However, the caller cannot hang onto this closure for too long. The 135 // tracing service will forcefully stop the tracing session without waiting 136 // for pending producers after TraceConfig.data_source_stop_timeout_ms 137 // (default: 5s, can be overridden by Consumers when starting a trace). 138 // If the closure is called after this timeout an error will be logged and 139 // the trace data emitted will not be present in the trace. No other 140 // functional side effects (e.g. crashes or corruptions) will happen. In 141 // other words, it is fine to accidentally hold onto this closure for too 142 // long but, if that happens, some tracing data will be lost. 143 virtual std::function<void()> HandleStopAsynchronously() const = 0; 144 145 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 146 uint32_t internal_instance_index = 0; 147 }; 148 // Invoked before tracing is stopped. 149 // 150 // Can be called from any thread. Blocking this for too long it's not a good 151 // idea and can cause deadlocks. Use HandleAsynchronously() to postpone 152 // disabling the data source instance. 153 virtual void OnStop(const StopArgs&); 154 155 class ClearIncrementalStateArgs { 156 public: 157 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 158 uint32_t internal_instance_index = 0; 159 }; 160 // Invoked before marking the thread local per-instance incremental state 161 // outdated. 162 // 163 // Can be called from any thread. 164 virtual void WillClearIncrementalState(const ClearIncrementalStateArgs&); 165 166 class FlushArgs { 167 public: 168 virtual ~FlushArgs(); 169 170 // HandleFlushAsynchronously() can be called to postpone acknowledging the 171 // flush request. This function returns a closure that must be invoked after 172 // the flush request has been processed. The returned closure can be called 173 // from any thread. 174 virtual std::function<void()> HandleFlushAsynchronously() const = 0; 175 176 // The index of this data source instance (0..kMaxDataSourceInstances - 1). 177 uint32_t internal_instance_index = 0; 178 179 // The reason and initiator of the flush. See flush_flags.h . 180 FlushFlags flush_flags; 181 }; 182 // Called when the tracing service requests a Flush. Users can override this 183 // to tell other threads to flush their TraceContext for this data source 184 // (the library cannot execute code on all the threads on its own). 185 // 186 // Can be called from any thread. Blocking this for too long it's not a good 187 // idea and can cause deadlocks. Use HandleAsynchronously() to postpone 188 // sending the flush acknowledgement to the service. 189 virtual void OnFlush(const FlushArgs&); 190 191 // Determines whether a startup session can be adopted by a service-initiated 192 // tracing session (i.e. whether their configs are compatible). 193 virtual bool CanAdoptStartupSession(const DataSourceConfig& startup_config, 194 const DataSourceConfig& service_config); 195 }; 196 197 struct DefaultDataSourceTraits { 198 // |IncrementalStateType| can optionally be used store custom per-sequence 199 // incremental data (e.g., interning tables). 200 using IncrementalStateType = void; 201 // |TlsStateType| can optionally be used to store custom per-sequence 202 // session data, which is not reset when incremental state is cleared 203 // (e.g. configuration options). 204 using TlsStateType = void; 205 206 // Allows overriding what type of thread-local state configuration the data 207 // source uses. By default every data source gets independent thread-local 208 // state, which means every instance uses separate trace writers and 209 // incremental state even on the same thread. Some data sources (most notably 210 // the track event data source) want to share trace writers and incremental 211 // state on the same thread. GetDataSourceTLSDefaultDataSourceTraits212 static internal::DataSourceThreadLocalState* GetDataSourceTLS( 213 internal::DataSourceStaticState* static_state, 214 internal::TracingTLS* root_tls) { 215 auto* ds_tls = &root_tls->data_sources_tls[static_state->index]; 216 // ds_tls->static_state can be: 217 // * nullptr 218 // * equal to static_state 219 // * equal to the static state of a different data source, in tests (when 220 // ResetForTesting() has been used) 221 // In any case, there's no need to do anything, the caller will reinitialize 222 // static_state. 223 return ds_tls; 224 } 225 }; 226 227 // Holds the type for a DataSource. Accessed by the static Trace() method 228 // fastpaths. This allows redefinitions under a component where a component 229 // specific export macro is used. 230 // Due to C2086 (redefinition) error on MSVC/clang-cl, internal::DataSourceType 231 // can't be a static data member. To avoid explicit specialization after 232 // instantiation error, type() needs to be in a template helper class that's 233 // instantiated independently from DataSource. See b/280777748. 234 template <typename DerivedDataSource, 235 typename DataSourceTraits = DefaultDataSourceTraits> 236 struct DataSourceHelper { typeDataSourceHelper237 static internal::DataSourceType& type() { 238 static perfetto::internal::DataSourceType type_; 239 return type_; 240 } 241 }; 242 243 // Templated base class meant to be derived by embedders to create a custom data 244 // source. DerivedDataSource must be the type of the derived class itself, e.g.: 245 // class MyDataSource : public DataSource<MyDataSource> {...}. 246 // 247 // |DataSourceTraits| allows customizing the behavior of the data source. See 248 // |DefaultDataSourceTraits|. 249 template <typename DerivedDataSource, 250 typename DataSourceTraits = DefaultDataSourceTraits> 251 class DataSource : public DataSourceBase { 252 struct DefaultTracePointTraits; 253 using Helper = DataSourceHelper<DerivedDataSource, DataSourceTraits>; 254 255 public: 256 // The BufferExhaustedPolicy to use for TraceWriters of this DataSource. 257 // Override this in your DataSource class to change the default, which is to 258 // drop data on shared memory overruns. 259 constexpr static BufferExhaustedPolicy kBufferExhaustedPolicy = 260 BufferExhaustedPolicy::kDrop; 261 262 // When this flag is false, we cannot have multiple instances of this data 263 // source. When a data source is already active and if we attempt 264 // to start another instance of that data source (via another tracing 265 // session), it will fail to start the second instance of data source. 266 static constexpr bool kSupportsMultipleInstances = true; 267 268 // When this flag is true, DataSource callbacks (OnSetup, OnStart, etc.) are 269 // called under the lock (the same that is used in GetDataSourceLocked 270 // function). This is not recommended because it can lead to deadlocks, but 271 // it was the default behavior for a long time and some embedders rely on it 272 // to protect concurrent access to the DataSource members. So we keep the 273 // "true" value as the default. 274 static constexpr bool kRequiresCallbacksUnderLock = true; 275 276 // Argument passed to the lambda function passed to Trace() (below). 277 class TraceContext { 278 public: 279 using TracePacketHandle = 280 ::protozero::MessageHandle<::perfetto::protos::pbzero::TracePacket>; 281 282 TraceContext(TraceContext&&) noexcept = default; ~TraceContext()283 ~TraceContext() { 284 // If the data source is being intercepted, flush the trace writer after 285 // each trace point to make sure the interceptor sees the data right away. 286 if (PERFETTO_UNLIKELY(tls_inst_->is_intercepted)) 287 Flush(); 288 } 289 290 // Adds an empty trace packet to the trace to ensure that the service can 291 // safely read the last event from the trace buffer. 292 // See PERFETTO_INTERNAL_ADD_EMPTY_EVENT macros for context. AddEmptyTracePacket()293 void AddEmptyTracePacket() { 294 // If nothing was written since the last empty packet, there's nothing to 295 // scrape, so adding more empty packets serves no purpose. 296 if (tls_inst_->trace_writer->written() == 297 tls_inst_->last_empty_packet_position) { 298 return; 299 } 300 tls_inst_->trace_writer->NewTracePacket(); 301 tls_inst_->last_empty_packet_position = 302 tls_inst_->trace_writer->written(); 303 } 304 NewTracePacket()305 TracePacketHandle NewTracePacket() { 306 return tls_inst_->trace_writer->NewTracePacket(); 307 } 308 309 // Forces a commit of the thread-local tracing data written so far to the 310 // service. This is almost never required (tracing data is periodically 311 // committed as trace pages are filled up) and has a non-negligible 312 // performance hit (requires an IPC + refresh of the current thread-local 313 // chunk). The only case when this should be used is when handling OnStop() 314 // asynchronously, to ensure sure that the data is committed before the 315 // Stop timeout expires. 316 // The TracePacketHandle obtained by the last NewTracePacket() call must be 317 // finalized before calling Flush() (either implicitly by going out of scope 318 // or by explicitly calling Finalize()). 319 // |cb| is an optional callback. When non-null it will request the 320 // service to ACK the flush and will be invoked on an internal thread after 321 // the service has acknowledged it. The callback might be NEVER INVOKED if 322 // the service crashes or the IPC connection is dropped. 323 void Flush(std::function<void()> cb = {}) { 324 tls_inst_->trace_writer->Flush(cb); 325 } 326 327 // Returns the number of bytes written on the current thread by the current 328 // data-source since its creation. 329 // This can be useful for splitting protos that might grow very large. written()330 uint64_t written() { return tls_inst_->trace_writer->written(); } 331 332 // Returns a RAII handle to access the data source instance, guaranteeing 333 // that it won't be deleted on another thread (because of trace stopping) 334 // while accessing it from within the Trace() lambda. 335 // The returned handle can be invalid (nullptr) if tracing is stopped 336 // immediately before calling this. The caller is supposed to check for its 337 // validity before using it. After checking, the handle is guaranteed to 338 // remain valid until the handle goes out of scope. GetDataSourceLocked()339 LockedHandle<DerivedDataSource> GetDataSourceLocked() const { 340 auto* internal_state = 341 Helper::type().static_state()->TryGet(instance_index_); 342 if (!internal_state) 343 return LockedHandle<DerivedDataSource>(); 344 std::unique_lock<std::recursive_mutex> lock(internal_state->lock); 345 return LockedHandle<DerivedDataSource>( 346 std::move(lock), 347 static_cast<DerivedDataSource*>(internal_state->data_source.get())); 348 } 349 350 // Post-condition: returned ptr will be non-null. GetCustomTlsState()351 typename DataSourceTraits::TlsStateType* GetCustomTlsState() { 352 PERFETTO_DCHECK(tls_inst_->data_source_custom_tls); 353 return reinterpret_cast<typename DataSourceTraits::TlsStateType*>( 354 tls_inst_->data_source_custom_tls.get()); 355 } 356 GetIncrementalState()357 typename DataSourceTraits::IncrementalStateType* GetIncrementalState() { 358 return static_cast<typename DataSourceTraits::IncrementalStateType*>( 359 Helper::type().GetIncrementalState(tls_inst_, instance_index_)); 360 } 361 362 private: 363 friend class DataSource; 364 template <typename, const internal::TrackEventCategoryRegistry*> 365 friend class internal::TrackEventDataSource; TraceContext(internal::DataSourceInstanceThreadLocalState * tls_inst,uint32_t instance_index)366 TraceContext(internal::DataSourceInstanceThreadLocalState* tls_inst, 367 uint32_t instance_index) 368 : tls_inst_(tls_inst), instance_index_(instance_index) {} 369 TraceContext(const TraceContext&) = delete; 370 TraceContext& operator=(const TraceContext&) = delete; 371 372 internal::DataSourceInstanceThreadLocalState* const tls_inst_; 373 uint32_t const instance_index_; 374 }; 375 376 // The main tracing method. Tracing code should call this passing a lambda as 377 // argument, with the following signature: void(TraceContext). 378 // The lambda will be called synchronously (i.e., always before Trace() 379 // returns) only if tracing is enabled and the data source has been enabled in 380 // the tracing config. 381 // The lambda can be called more than once per Trace() call, in the case of 382 // concurrent tracing sessions (or even if the data source is instantiated 383 // twice within the same trace config). 384 template <typename Lambda> Trace(Lambda tracing_fn)385 static void Trace(Lambda tracing_fn) { 386 CallIfEnabled<DefaultTracePointTraits>([&tracing_fn](uint32_t instances) { 387 TraceWithInstances<DefaultTracePointTraits>(instances, 388 std::move(tracing_fn)); 389 }); 390 } 391 392 // An efficient trace point guard for checking if this data source is active. 393 // |callback| is a function which will only be called if there are active 394 // instances. It is given an instance state parameter, which should be passed 395 // to TraceWithInstances() to actually record trace data. 396 template <typename Traits = DefaultTracePointTraits, typename Callback> 397 static void CallIfEnabled(Callback callback, 398 typename Traits::TracePointData trace_point_data = 399 {}) PERFETTO_ALWAYS_INLINE { 400 // |instances| is a per-class bitmap that tells: 401 // 1. If the data source is enabled at all. 402 // 2. The index of the slot within 403 // internal::DataSourceStaticState::instances that holds the instance 404 // state. In turn this allows to map the data source to the tracing 405 // session and buffers. 406 // memory_order_relaxed is okay because: 407 // - |instances| is re-read with an acquire barrier below if this succeeds. 408 // - The code between this point and the acquire-load is based on static 409 // storage which has indefinite lifetime. 410 uint32_t instances = Traits::GetActiveInstances(trace_point_data) 411 ->load(std::memory_order_relaxed); 412 413 // This is the tracing fast-path. Bail out immediately if tracing is not 414 // enabled (or tracing is enabled but not for this data source). 415 if (PERFETTO_LIKELY(!instances)) 416 return; 417 callback(instances); 418 } 419 420 // The "lower half" of a trace point which actually performs tracing after 421 // this data source has been determined to be active. 422 // |instances| must be the instance state value retrieved through 423 // CallIfEnabled(). 424 // |tracing_fn| will be called to record trace data as in Trace(). 425 // 426 // |trace_point_data| is an optional parameter given to |Traits:: 427 // GetActiveInstances| to make it possible to use custom storage for 428 // the data source enabled state. This is, for example, used by TrackEvent to 429 // implement per-tracing category enabled states. 430 template <typename Traits = DefaultTracePointTraits, typename Lambda> 431 static void TraceWithInstances( 432 uint32_t cached_instances, 433 Lambda tracing_fn, 434 typename Traits::TracePointData trace_point_data = {}) { 435 PERFETTO_DCHECK(cached_instances); 436 437 if (!Helper::type().template TracePrologue<DataSourceTraits, Traits>( 438 &tls_state_, &cached_instances, trace_point_data)) { 439 return; 440 } 441 442 for (internal::DataSourceType::InstancesIterator it = 443 Helper::type().template BeginIteration<Traits>( 444 cached_instances, tls_state_, trace_point_data); 445 it.instance; Helper::type().template NextIteration<Traits>( 446 &it, tls_state_, trace_point_data)) { 447 tracing_fn(TraceContext(it.instance, it.i)); 448 } 449 450 Helper::type().TraceEpilogue(tls_state_); 451 } 452 453 // Registers the data source on all tracing backends, including ones that 454 // connect after the registration. Doing so enables the data source to receive 455 // Setup/Start/Stop notifications and makes the Trace() method work when 456 // tracing is enabled and the data source is selected. 457 // This must be called after Tracing::Initialize(). 458 // Can return false to signal failure if attemping to register more than 459 // kMaxDataSources (32) data sources types or if tracing hasn't been 460 // initialized. 461 // The optional |constructor_args| will be passed to the data source when it 462 // is constructed. 463 template <class... Args> Register(const DataSourceDescriptor & descriptor,const Args &...constructor_args)464 static bool Register(const DataSourceDescriptor& descriptor, 465 const Args&... constructor_args) { 466 // Silences -Wunused-variable warning in case the trace method is not used 467 // by the translation unit that declares the data source. 468 (void)tls_state_; 469 470 auto factory = [constructor_args...]() { 471 return std::unique_ptr<DataSourceBase>( 472 new DerivedDataSource(constructor_args...)); 473 }; 474 constexpr bool no_flush = 475 std::is_same_v<decltype(&DerivedDataSource::OnFlush), 476 decltype(&DataSourceBase::OnFlush)>; 477 internal::DataSourceParams params{ 478 DerivedDataSource::kSupportsMultipleInstances, 479 DerivedDataSource::kRequiresCallbacksUnderLock}; 480 return Helper::type().Register( 481 descriptor, factory, params, DerivedDataSource::kBufferExhaustedPolicy, 482 no_flush, 483 GetCreateTlsFn( 484 static_cast<typename DataSourceTraits::TlsStateType*>(nullptr)), 485 GetCreateIncrementalStateFn( 486 static_cast<typename DataSourceTraits::IncrementalStateType*>( 487 nullptr)), 488 nullptr); 489 } 490 491 // Updates the data source descriptor. UpdateDescriptor(const DataSourceDescriptor & descriptor)492 static void UpdateDescriptor(const DataSourceDescriptor& descriptor) { 493 Helper::type().UpdateDescriptor(descriptor); 494 } 495 496 private: 497 friend ::perfetto::test::DataSourceInternalForTest; 498 friend ::perfetto::shlib::TrackEvent; 499 // Traits for customizing the behavior of a specific trace point. 500 struct DefaultTracePointTraits { 501 // By default, every call to DataSource::Trace() will record trace events 502 // for every active instance of that data source. A single trace point can, 503 // however, use a custom set of enable flags for more fine grained control 504 // of when that trace point is active. 505 // 506 // DANGER: when doing this, the data source must use the appropriate memory 507 // fences when changing the state of the bitmap. 508 // 509 // |TraceWithInstances| may be optionally given an additional parameter for 510 // looking up the enable flags. That parameter is passed as |TracePointData| 511 // to |GetActiveInstances|. This is, for example, used by TrackEvent to 512 // implement per-category enabled states. 513 struct TracePointData {}; GetActiveInstancesDefaultTracePointTraits514 static constexpr std::atomic<uint32_t>* GetActiveInstances(TracePointData) { 515 return Helper::type().valid_instances(); 516 } 517 }; 518 519 template <typename T> 520 static internal::DataSourceInstanceThreadLocalState::ObjectWithDeleter CreateIncrementalState(internal::DataSourceInstanceThreadLocalState *,uint32_t,void *)521 CreateIncrementalState(internal::DataSourceInstanceThreadLocalState*, 522 uint32_t, 523 void*) { 524 return internal::DataSourceInstanceThreadLocalState::ObjectWithDeleter( 525 reinterpret_cast<void*>(new T()), 526 [](void* p) { delete reinterpret_cast<T*>(p); }); 527 } 528 529 // The second parameter here is used to specialize the case where there is no 530 // incremental state type. 531 template <typename T> 532 static internal::DataSourceType::CreateIncrementalStateFn GetCreateIncrementalStateFn(const T *)533 GetCreateIncrementalStateFn(const T*) { 534 return &CreateIncrementalState<T>; 535 } 536 537 static internal::DataSourceType::CreateIncrementalStateFn GetCreateIncrementalStateFn(const void *)538 GetCreateIncrementalStateFn(const void*) { 539 return nullptr; 540 } 541 542 template <typename T> 543 static internal::DataSourceInstanceThreadLocalState::ObjectWithDeleter CreateDataSourceCustomTls(internal::DataSourceInstanceThreadLocalState * tls_inst,uint32_t instance_index,void *)544 CreateDataSourceCustomTls( 545 internal::DataSourceInstanceThreadLocalState* tls_inst, 546 uint32_t instance_index, 547 void*) { 548 return internal::DataSourceInstanceThreadLocalState::ObjectWithDeleter( 549 reinterpret_cast<void*>(new T(TraceContext(tls_inst, instance_index))), 550 [](void* p) { delete reinterpret_cast<T*>(p); }); 551 } 552 553 // The second parameter here is used to specialize the case where there is no 554 // tls state type. 555 template <typename T> GetCreateTlsFn(const T *)556 static internal::DataSourceType::CreateCustomTlsFn GetCreateTlsFn(const T*) { 557 return &CreateDataSourceCustomTls<T>; 558 } 559 GetCreateTlsFn(const void *)560 static internal::DataSourceType::CreateCustomTlsFn GetCreateTlsFn( 561 const void*) { 562 return nullptr; 563 } 564 565 // This TLS object is a cached raw pointer and has deliberately no destructor. 566 // The Platform implementation is supposed to create and manage the lifetime 567 // of the Platform::ThreadLocalObject and take care of destroying it. 568 // This is because non-POD thread_local variables have subtleties (global 569 // destructors) that we need to defer to the embedder. In chromium's platform 570 // implementation, for instance, the tls slot is implemented using 571 // chromium's base::ThreadLocalStorage. 572 static thread_local internal::DataSourceThreadLocalState* tls_state_; 573 }; 574 575 // static 576 template <typename T, typename D> 577 thread_local internal::DataSourceThreadLocalState* DataSource<T, D>::tls_state_; 578 579 } // namespace perfetto 580 581 // If placed at the end of a macro declaration, eats the semicolon at the end of 582 // the macro invocation (e.g., "MACRO(...);") to avoid warnings about extra 583 // semicolons. 584 #define PERFETTO_INTERNAL_SWALLOW_SEMICOLON() \ 585 extern int perfetto_internal_unused 586 587 // This macro must be used once for each data source next to the data source's 588 // declaration. 589 #define PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(...) \ 590 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS( \ 591 PERFETTO_COMPONENT_EXPORT, __VA_ARGS__) 592 593 // Similar to `PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS` but it also takes 594 // custom attributes, which are useful when DataSource is defined in a component 595 // where a component specific export macro is used. 596 #define PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(attrs, ...) \ 597 template <> \ 598 attrs perfetto::internal::DataSourceType& \ 599 perfetto::DataSourceHelper<__VA_ARGS__>::type() 600 601 // This macro must be used once for each data source in one source file to 602 // allocate static storage for the data source's static state. 603 #define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(...) \ 604 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS( \ 605 PERFETTO_COMPONENT_EXPORT, __VA_ARGS__) 606 607 // Similar to `PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS` but it also takes 608 // custom attributes, which are useful when DataSource is defined in a component 609 // where a component specific export macro is used. 610 #define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(attrs, ...) \ 611 template <> \ 612 perfetto::internal::DataSourceType& \ 613 perfetto::DataSourceHelper<__VA_ARGS__>::type() { \ 614 static perfetto::internal::DataSourceType type_; \ 615 return type_; \ 616 } \ 617 PERFETTO_INTERNAL_SWALLOW_SEMICOLON() 618 619 #endif // INCLUDE_PERFETTO_TRACING_DATA_SOURCE_H_ 620