1 // Copyright 2016 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifdef UNSAFE_BUFFERS_BUILD 6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. 7 #pragma allow_unsafe_buffers 8 #endif 9 10 #ifndef BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_ 11 #define BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_ 12 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #include <atomic> 17 18 #include "base/base_export.h" 19 #include "base/check_op.h" 20 #include "base/containers/span.h" 21 #include "base/memory/raw_ptr.h" 22 #include "base/trace_event/builtin_categories.h" 23 #include "base/trace_event/common/trace_event_common.h" 24 #include "base/trace_event/trace_category.h" 25 #include "build/build_config.h" 26 27 namespace base { 28 namespace trace_event { 29 30 class TraceCategoryTest; 31 class TraceLog; 32 33 // Allows fast and thread-safe acces to the state of all tracing categories. 34 // All the methods in this class can be concurrently called on multiple threads, 35 // unless otherwise noted (e.g., GetOrCreateCategoryLocked). 36 // The reason why this is a fully static class with global state is to allow to 37 // statically define known categories as global linker-initialized structs, 38 // without requiring static initializers. 39 class BASE_EXPORT CategoryRegistry { 40 public: 41 // Known categories. 42 static TraceCategory* const kCategoryMetadata; 43 static TraceCategory* const kCategoryAlreadyShutdown; 44 45 // Returns a category entry from the Category.state_ptr() pointer. 46 // TODO(primiano): trace macros should just keep a pointer to the entire 47 // TraceCategory, not just the enabled state pointer. That would remove the 48 // need for this function and make everything cleaner at no extra cost (as 49 // long as the |state_| is the first field of the struct, which can be 50 // guaranteed via static_assert, see TraceCategory ctor). 51 static const TraceCategory* GetCategoryByStatePtr( 52 const uint8_t* category_state); 53 54 // Returns a category from its name or nullptr if not found. 55 // The output |category| argument is an undefinitely lived pointer to the 56 // TraceCategory owned by the registry. TRACE_EVENTx macros will cache this 57 // pointer and use it for checks in their fast-paths. 58 static TraceCategory* GetCategoryByName(const char* category_name); 59 60 // Returns a built-in category from its name or nullptr if not found at 61 // compile-time. The return value is an undefinitely lived pointer to the 62 // TraceCategory owned by the registry. GetBuiltinCategoryByName(const char * category_group)63 static constexpr TraceCategory* GetBuiltinCategoryByName( 64 const char* category_group) { 65 #if BUILDFLAG(IS_WIN) && defined(COMPONENT_BUILD) 66 // The address cannot be evaluated at compile-time in Windows component 67 // builds. 68 return nullptr; 69 #else 70 for (size_t i = 0; i < BuiltinCategories::Size(); ++i) { 71 if (StrEqConstexpr(category_group, BuiltinCategories::At(i))) 72 return &categories_[i]; 73 } 74 return nullptr; 75 #endif 76 } 77 78 // Returns whether |category| points at one of the meta categories that 79 // shouldn't be displayed in the tracing UI. 80 static bool IsMetaCategory(const TraceCategory* category); 81 82 private: 83 friend class TraceCategoryTest; 84 friend class TraceLog; 85 using CategoryInitializerFn = void (*)(TraceCategory*); 86 87 // The max number of trace categories that can be recorded. 88 static constexpr size_t kMaxCategories = 350; 89 90 // Checks that there is enough space for all builtin categories. 91 static_assert(BuiltinCategories::Size() <= kMaxCategories, 92 "kMaxCategories must be greater than kNumBuiltinCategories"); 93 94 // Only for debugging/testing purposes, is a no-op on release builds. 95 static void Initialize(); 96 97 // Resets the state of all categories, to clear up the state between tests. 98 static void ResetForTesting(); 99 100 // Used to get/create a category in the slow-path. If the category exists 101 // already, this has the same effect of GetCategoryByName and returns false. 102 // If not, a new category is created and the CategoryInitializerFn is invoked 103 // before retuning true. The caller must guarantee serialization: either call 104 // this method from a single thread or hold a lock when calling this. 105 static bool GetOrCreateCategoryLocked(const char* category_name, 106 CategoryInitializerFn, 107 TraceCategory**); 108 109 // Allows to iterate over the valid categories in a for-each loop. 110 // This includes builtin categories such as __metadata. 111 static base::span<TraceCategory> GetAllCategories(); 112 113 // Returns whether |category| correctly points at |categories_| array entry. 114 static bool IsValidCategoryPtr(const TraceCategory* category); 115 116 // The static array of trace categories. 117 static TraceCategory categories_[kMaxCategories]; 118 119 // Contains the number of created categories. 120 static std::atomic<size_t> category_index_; 121 }; 122 123 } // namespace trace_event 124 } // namespace base 125 126 #endif // BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_ 127