prioritized_task_runner.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright (c) 2018 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 NET_BASE_PRIORITIZED_TASK_RUNNER_H_
  5. #define NET_BASE_PRIORITIZED_TASK_RUNNER_H_
  6. #include <stdint.h>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "base/callback.h"
  11. #include "base/location.h"
  12. #include "base/memory/ref_counted.h"
  13. #include "base/synchronization/lock.h"
  14. #include "base/task/post_task_and_reply_with_result_internal.h"
  15. #include "base/task/task_traits.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "net/base/net_export.h"
  18. namespace base {
  19. class TaskRunner;
  20. } // namespace base
  21. namespace net {
  22. namespace internal {
  23. template <typename ReturnType>
  24. void ReturnAsParamAdapter(base::OnceCallback<ReturnType()> func,
  25. ReturnType* result) {
  26. *result = std::move(func).Run();
  27. }
  28. // Adapts a T* result to a callblack that expects a T.
  29. template <typename TaskReturnType, typename ReplyArgType>
  30. void ReplyAdapter(base::OnceCallback<void(ReplyArgType)> callback,
  31. TaskReturnType* result) {
  32. std::move(callback).Run(std::move(*result));
  33. }
  34. } // namespace internal
  35. // PrioritizedTaskRunner allows for prioritization of posted tasks and their
  36. // replies. It provides up to 2^32 priority levels. All tasks posted via the
  37. // PrioritizedTaskRunner will run in priority order. All replies from
  38. // PostTaskAndReply will also run in priority order. Be careful, as it is
  39. // possible to starve a task.
  40. class NET_EXPORT_PRIVATE PrioritizedTaskRunner
  41. : public base::RefCountedThreadSafe<PrioritizedTaskRunner> {
  42. public:
  43. enum class ReplyRunnerType { kStandard, kPrioritized };
  44. explicit PrioritizedTaskRunner(const base::TaskTraits& task_traits);
  45. PrioritizedTaskRunner(const PrioritizedTaskRunner&) = delete;
  46. PrioritizedTaskRunner& operator=(const PrioritizedTaskRunner&) = delete;
  47. // Similar to TaskRunner::PostTaskAndReply, except that the task runs at
  48. // |priority|. Priority 0 is the highest priority and will run before other
  49. // priority values. Multiple tasks with the same |priority| value are run in
  50. // order of posting. The replies are also run in prioritized order on the
  51. // calling taskrunner.
  52. void PostTaskAndReply(const base::Location& from_here,
  53. base::OnceClosure task,
  54. base::OnceClosure reply,
  55. uint32_t priority);
  56. // Similar to TaskRunner::PostTaskAndReplyWithResult, except that the task
  57. // runs at |priority|. See PostTaskAndReply for a description of |priority|.
  58. template <typename TaskReturnType, typename ReplyArgType>
  59. void PostTaskAndReplyWithResult(const base::Location& from_here,
  60. base::OnceCallback<TaskReturnType()> task,
  61. base::OnceCallback<void(ReplyArgType)> reply,
  62. uint32_t priority) {
  63. TaskReturnType* result = new TaskReturnType();
  64. return PostTaskAndReply(
  65. from_here,
  66. BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
  67. std::move(task), result),
  68. BindOnce(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
  69. std::move(reply), base::Owned(result)),
  70. priority);
  71. }
  72. void SetTaskRunnerForTesting(scoped_refptr<base::TaskRunner> task_runner) {
  73. task_runner_for_testing_ = std::move(task_runner);
  74. }
  75. private:
  76. friend class base::RefCountedThreadSafe<PrioritizedTaskRunner>;
  77. struct Job {
  78. Job(const base::Location& from_here,
  79. base::OnceClosure task,
  80. base::OnceClosure reply,
  81. uint32_t priority,
  82. uint32_t task_count);
  83. Job();
  84. Job(const Job&) = delete;
  85. Job& operator=(const Job&) = delete;
  86. ~Job();
  87. Job(Job&& other);
  88. Job& operator=(Job&& other);
  89. base::Location from_here;
  90. base::OnceClosure task;
  91. base::OnceClosure reply;
  92. uint32_t priority = 0;
  93. uint32_t task_count = 0;
  94. };
  95. struct JobComparer {
  96. bool operator()(const Job& left, const Job& right) {
  97. if (left.priority == right.priority)
  98. return left.task_count > right.task_count;
  99. return left.priority > right.priority;
  100. }
  101. };
  102. void RunTaskAndPostReply();
  103. void RunReply();
  104. ~PrioritizedTaskRunner();
  105. // TODO(jkarlin): Replace the heaps with std::priority_queue once it
  106. // supports move-only types.
  107. // Accessed on both task_runner_ and the reply task runner.
  108. std::vector<Job> task_job_heap_;
  109. base::Lock task_job_heap_lock_;
  110. std::vector<Job> reply_job_heap_;
  111. base::Lock reply_job_heap_lock_;
  112. const base::TaskTraits task_traits_;
  113. scoped_refptr<base::TaskRunner> task_runner_for_testing_;
  114. // Used to preserve order of jobs of equal priority. This can overflow and
  115. // cause periodic priority inversion. This should be infrequent enough to be
  116. // of negligible impact.
  117. uint32_t task_count_ = 0;
  118. };
  119. } // namespace net
  120. #endif // NET_BASE_PRIORITIZED_TASK_RUNNER_H_