scoped_thread_priority.h 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_THREADING_SCOPED_THREAD_PRIORITY_H_
  5. #define BASE_THREADING_SCOPED_THREAD_PRIORITY_H_
  6. #include <atomic>
  7. #include "base/base_export.h"
  8. #include "base/compiler_specific.h"
  9. #include "base/location.h"
  10. #include "base/macros.h"
  11. #include "base/optional.h"
  12. #include "build/build_config.h"
  13. namespace base {
  14. class Location;
  15. enum class ThreadPriority : int;
  16. // INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(name) produces an identifier by
  17. // appending the current line number to |name|. This is used to avoid name
  18. // collisions from variables defined inside a macro.
  19. #define INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT(a, b) a##b
  20. // CONCAT1 provides extra level of indirection so that __LINE__ macro expands.
  21. #define INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT1(a, b) \
  22. INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT(a, b)
  23. #define INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(name) \
  24. INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT1(name, __LINE__)
  25. // All code that may load a DLL on a background thread must be surrounded by a
  26. // scope that starts with this macro.
  27. //
  28. // Example:
  29. // Foo();
  30. // {
  31. // SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
  32. // LoadMyDll();
  33. // }
  34. // Bar();
  35. //
  36. // The macro raises the thread priority to NORMAL for the scope if no other
  37. // thread has completed the current scope already (multiple threads can racily
  38. // begin the initialization and will all be boosted for it). On Windows, loading
  39. // a DLL on a background thread can lead to a priority inversion on the loader
  40. // lock and cause huge janks.
  41. #define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY() \
  42. static std::atomic_bool INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \
  43. already_loaded){false}; \
  44. base::internal::ScopedMayLoadLibraryAtBackgroundPriority \
  45. INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \
  46. scoped_may_load_library_at_background_priority)( \
  47. FROM_HERE, \
  48. &INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(already_loaded));
  49. // Like SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY, but raises the thread
  50. // priority every time the scope is entered. Use this around code that may
  51. // conditionally load a DLL each time it is executed, or which repeatedly loads
  52. // and unloads DLLs.
  53. #define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY() \
  54. base::internal::ScopedMayLoadLibraryAtBackgroundPriority \
  55. INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \
  56. scoped_may_load_library_at_background_priority)(FROM_HERE, nullptr);
  57. namespace internal {
  58. class BASE_EXPORT ScopedMayLoadLibraryAtBackgroundPriority {
  59. public:
  60. // Boosts thread priority to NORMAL within its scope if |already_loaded| is
  61. // nullptr or set to false.
  62. explicit ScopedMayLoadLibraryAtBackgroundPriority(
  63. const Location& from_here,
  64. std::atomic_bool* already_loaded);
  65. ~ScopedMayLoadLibraryAtBackgroundPriority();
  66. private:
  67. #if defined(OS_WIN)
  68. // The original priority when invoking entering the scope().
  69. base::Optional<ThreadPriority> original_thread_priority_;
  70. std::atomic_bool* const already_loaded_;
  71. #endif
  72. DISALLOW_COPY_AND_ASSIGN(ScopedMayLoadLibraryAtBackgroundPriority);
  73. };
  74. } // namespace internal
  75. } // namespace base
  76. #endif // BASE_THREADING_SCOPED_THREAD_PRIORITY_H_