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