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 match ThreadType::kDefault for the 35 // scope if no other thread has completed the current scope already (multiple 36 // threads can racily begin the initialization and will all be boosted for it). 37 // On Windows, loading a DLL on a background thread can lead to a priority 38 // inversion on the loader 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. `target_thread_type` must be lower 55 // priority than kRealtimeAudio, since realtime priority should only be used by 56 // dedicated media threads. 57 class BASE_EXPORT ScopedBoostPriority { 58 public: 59 explicit ScopedBoostPriority(ThreadType target_thread_type); 60 ~ScopedBoostPriority(); 61 62 ScopedBoostPriority(const ScopedBoostPriority&) = delete; 63 ScopedBoostPriority& operator=(const ScopedBoostPriority&) = delete; 64 65 private: 66 std::optional<ThreadType> original_thread_type_; 67 }; 68 69 namespace internal { 70 71 class BASE_EXPORT ScopedMayLoadLibraryAtBackgroundPriority { 72 public: 73 // Boosts thread priority to match ThreadType::kDefault within its scope if 74 // `already_loaded` is nullptr or set to false. 75 explicit ScopedMayLoadLibraryAtBackgroundPriority( 76 const Location& from_here, 77 std::atomic_bool* already_loaded); 78 79 ScopedMayLoadLibraryAtBackgroundPriority( 80 const ScopedMayLoadLibraryAtBackgroundPriority&) = delete; 81 ScopedMayLoadLibraryAtBackgroundPriority& operator=( 82 const ScopedMayLoadLibraryAtBackgroundPriority&) = delete; 83 84 ~ScopedMayLoadLibraryAtBackgroundPriority(); 85 86 private: 87 #if BUILDFLAG(IS_WIN) 88 // The original priority when invoking entering the scope(). 89 std::optional<ThreadType> original_thread_type_; 90 const raw_ptr<std::atomic_bool> already_loaded_; 91 #endif 92 }; 93 94 } // namespace internal 95 96 } // namespace base 97 98 #endif // BASE_THREADING_SCOPED_THREAD_PRIORITY_H_ 99