File: scoped_thread_priority.h

package info (click to toggle)
chromium 145.0.7632.109-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,974,804 kB
  • sloc: cpp: 36,197,696; ansic: 7,602,761; javascript: 3,563,590; python: 1,649,324; xml: 838,427; asm: 717,087; pascal: 185,708; sh: 88,786; perl: 88,718; objc: 79,984; sql: 59,811; cs: 42,452; fortran: 24,101; makefile: 21,022; tcl: 15,277; php: 14,022; yacc: 9,066; ruby: 7,553; awk: 3,720; lisp: 3,233; lex: 1,328; ada: 727; jsp: 228; sed: 36
file content (167 lines) | stat: -rw-r--r-- 6,286 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_THREADING_SCOPED_THREAD_PRIORITY_H_
#define BASE_THREADING_SCOPED_THREAD_PRIORITY_H_

#include <atomic>
#include <optional>

#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/macros/uniquify.h"
#include "base/memory/raw_ptr.h"
#include "base/task/task_observer.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_handle.h"
#endif

namespace base {

class Location;
enum class ThreadType : int;

// All code that may load a DLL on a background thread must be surrounded by a
// scope that starts with this macro.
//
// Example:
//   Foo();
//   {
//     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
//     LoadMyDll();
//   }
//   Bar();
//
// The macro raises the thread priority to match ThreadType::kDefault for the
// scope if no other thread has completed the current scope already (multiple
// threads can racily begin the initialization and will all be boosted for it).
// On Windows, loading a DLL on a background thread can lead to a priority
// inversion on the loader lock and cause huge janks.
#define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY()                  \
  static std::atomic_bool BASE_UNIQUIFY(already_loaded){false};           \
  base::internal::ScopedMayLoadLibraryAtBackgroundPriority BASE_UNIQUIFY( \
      scoped_may_load_library_at_background_priority)(                    \
      FROM_HERE, &BASE_UNIQUIFY(already_loaded));

// Like SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY, but raises the thread
// priority every time the scope is entered. Use this around code that may
// conditionally load a DLL each time it is executed, or which repeatedly loads
// and unloads DLLs.
#define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY()       \
  base::internal::ScopedMayLoadLibraryAtBackgroundPriority BASE_UNIQUIFY( \
      scoped_may_load_library_at_background_priority)(FROM_HERE, nullptr);

// Boosts the current thread's priority to match the priority of threads of
// `target_thread_type` in this scope. `target_thread_type` must be lower
// priority than kRealtimeAudio, since realtime priority should only be used by
// dedicated media threads.
class BASE_EXPORT ScopedBoostPriority {
 public:
  explicit ScopedBoostPriority(ThreadType target_thread_type);
  ~ScopedBoostPriority();

  ScopedBoostPriority(const ScopedBoostPriority&) = delete;
  ScopedBoostPriority& operator=(const ScopedBoostPriority&) = delete;

 private:
  std::optional<ThreadType> original_thread_type_;
};

// Allows another thread to temporarily boost the current thread's priority to
// match the priority of threads of `target_thread_type`. The priority is reset
// when the object is destroyed, which must happens on the current thread.
// `target_thread_type` must be lower priority than kRealtimeAudio, since
// realtime priority should only be used by dedicated media threads.
class BASE_EXPORT ScopedBoostablePriority {
 public:
  ScopedBoostablePriority();
  ~ScopedBoostablePriority();

  ScopedBoostablePriority(const ScopedBoostablePriority&) = delete;
  ScopedBoostablePriority& operator=(const ScopedBoostablePriority& other) =
      delete;

  // Boosts the priority of the thread where this ScopedBoostablePriority was
  // created. Can be called from any thread, but requires proper external
  // synchronization with the constructor, destructor and any other call to
  // BoostPriority/Reset(). If called multiple times, only the first call takes
  // effect.
  bool BoostPriority(ThreadType target_thread_type);

  // Resets the priority of the thread where this ScopedBoostablePriority was
  // created to its original priority. Can be called from any thread, but
  // requires proper external synchronization with the constructor, destructor
  // and any other call to BoostPriority/Reset().
  void Reset();

 private:
  const ThreadType initial_thread_type_;
  PlatformThreadHandle thread_handle_;
#if BUILDFLAG(IS_WIN)
  win::ScopedHandle scoped_handle_;
#endif
  bool did_override_priority_{false};
  internal::PlatformPriorityOverride priority_override_handle_;
  THREAD_CHECKER(thread_checker_);
};

// This wraps ScopedBoostPriority with a callback to determine whether
// the priority should be boosted or not before every task execution.
class BASE_EXPORT TaskMonitoringScopedBoostPriority : public TaskObserver {
 public:
  explicit TaskMonitoringScopedBoostPriority(
      ThreadType target_thread_type,
      RepeatingCallback<bool()> should_boost_callback);
  ~TaskMonitoringScopedBoostPriority() override;

  TaskMonitoringScopedBoostPriority(const TaskMonitoringScopedBoostPriority&) =
      delete;
  TaskMonitoringScopedBoostPriority& operator=(
      const TaskMonitoringScopedBoostPriority&) = delete;

  // TaskObserver implementation:
  void WillProcessTask(const PendingTask& pending_task,
                       bool was_blocked_or_low_priority) override;
  void DidProcessTask(const PendingTask& pending_task) override {}

 private:
  std::optional<ScopedBoostPriority> scoped_boost_priority_;
  ThreadType target_thread_type_;
  RepeatingCallback<bool()> should_boost_callback_;
};

namespace internal {

class BASE_EXPORT ScopedMayLoadLibraryAtBackgroundPriority {
 public:
  // Boosts thread priority to match ThreadType::kDefault within its scope if
  // `already_loaded` is nullptr or set to false.
  explicit ScopedMayLoadLibraryAtBackgroundPriority(
      const Location& from_here,
      std::atomic_bool* already_loaded);

  ScopedMayLoadLibraryAtBackgroundPriority(
      const ScopedMayLoadLibraryAtBackgroundPriority&) = delete;
  ScopedMayLoadLibraryAtBackgroundPriority& operator=(
      const ScopedMayLoadLibraryAtBackgroundPriority&) = delete;

  ~ScopedMayLoadLibraryAtBackgroundPriority();

 private:
#if BUILDFLAG(IS_WIN)
  // The original priority when invoking entering the scope().
  std::optional<ThreadType> original_thread_type_;
  const raw_ptr<std::atomic_bool> already_loaded_;
#endif
};

}  // namespace internal

}  // namespace base

#endif  // BASE_THREADING_SCOPED_THREAD_PRIORITY_H_