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