xref: /aosp_15_r20/external/cronet/base/threading/scoped_thread_priority.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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