• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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