1 // Copyright 2019 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 #ifndef BASE_THREADING_SCOPED_THREAD_PRIORITY_H_ 6 #define BASE_THREADING_SCOPED_THREAD_PRIORITY_H_ 7 8 #include <atomic> 9 10 #include "base/base_export.h" 11 #include "base/compiler_specific.h" 12 #include "base/location.h" 13 #include "base/memory/raw_ptr.h" 14 #include "build/build_config.h" 15 #include "third_party/abseil-cpp/absl/types/optional.h" 16 17 namespace base { 18 19 class Location; 20 enum class ThreadType : int; 21 22 // INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(name) produces an identifier by 23 // appending the current line number to |name|. This is used to avoid name 24 // collisions from variables defined inside a macro. 25 #define INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT(a, b) a##b 26 // CONCAT1 provides extra level of indirection so that __LINE__ macro expands. 27 #define INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT1(a, b) \ 28 INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT(a, b) 29 #define INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(name) \ 30 INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT1(name, __LINE__) 31 32 // All code that may load a DLL on a background thread must be surrounded by a 33 // scope that starts with this macro. 34 // 35 // Example: 36 // Foo(); 37 // { 38 // SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); 39 // LoadMyDll(); 40 // } 41 // Bar(); 42 // 43 // The macro raises the thread priority to NORMAL for the scope if no other 44 // thread has completed the current scope already (multiple threads can racily 45 // begin the initialization and will all be boosted for it). On Windows, loading 46 // a DLL on a background thread can lead to a priority inversion on the loader 47 // lock and cause huge janks. 48 #define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY() \ 49 static std::atomic_bool INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \ 50 already_loaded){false}; \ 51 base::internal::ScopedMayLoadLibraryAtBackgroundPriority \ 52 INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \ 53 scoped_may_load_library_at_background_priority)( \ 54 FROM_HERE, \ 55 &INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(already_loaded)); 56 57 // Like SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY, but raises the thread 58 // priority every time the scope is entered. Use this around code that may 59 // conditionally load a DLL each time it is executed, or which repeatedly loads 60 // and unloads DLLs. 61 #define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY() \ 62 base::internal::ScopedMayLoadLibraryAtBackgroundPriority \ 63 INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \ 64 scoped_may_load_library_at_background_priority)(FROM_HERE, nullptr); 65 66 // Boosts the current thread's priority to match the priority of threads of 67 // |target_thread_type| in this scope. 68 class BASE_EXPORT ScopedBoostPriority { 69 public: 70 explicit ScopedBoostPriority(ThreadType target_thread_type); 71 ~ScopedBoostPriority(); 72 73 ScopedBoostPriority(const ScopedBoostPriority&) = delete; 74 ScopedBoostPriority& operator=(const ScopedBoostPriority&) = delete; 75 76 private: 77 absl::optional<ThreadType> original_thread_type_; 78 }; 79 80 namespace internal { 81 82 class BASE_EXPORT ScopedMayLoadLibraryAtBackgroundPriority { 83 public: 84 // Boosts thread priority to NORMAL within its scope if |already_loaded| is 85 // nullptr or set to false. 86 explicit ScopedMayLoadLibraryAtBackgroundPriority( 87 const Location& from_here, 88 std::atomic_bool* already_loaded); 89 90 ScopedMayLoadLibraryAtBackgroundPriority( 91 const ScopedMayLoadLibraryAtBackgroundPriority&) = delete; 92 ScopedMayLoadLibraryAtBackgroundPriority& operator=( 93 const ScopedMayLoadLibraryAtBackgroundPriority&) = delete; 94 95 ~ScopedMayLoadLibraryAtBackgroundPriority(); 96 97 private: 98 #if BUILDFLAG(IS_WIN) 99 // The original priority when invoking entering the scope(). 100 absl::optional<ThreadType> original_thread_type_; 101 const raw_ptr<std::atomic_bool> already_loaded_; 102 #endif 103 }; 104 105 } // namespace internal 106 107 } // namespace base 108 109 #endif // BASE_THREADING_SCOPED_THREAD_PRIORITY_H_ 110