blob: 33014e46ce5341b86cd3feb22d58bb3c20b2accd [file] [log] [blame]
Josh Karlindd9a5d142018-06-06 00:35:481// 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
5#ifndef NET_BASE_PRIORITIZED_TASK_RUNNER_H_
6#define NET_BASE_PRIORITIZED_TASK_RUNNER_H_
7
8#include <stdint.h>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/callback.h"
13#include "base/location.h"
14#include "base/memory/ref_counted.h"
15#include "base/post_task_and_reply_with_result_internal.h"
16#include "base/synchronization/lock.h"
17#include "base/threading/thread_task_runner_handle.h"
18#include "net/base/net_export.h"
19
20namespace base {
21class TaskRunner;
22} // namespace base
23
24namespace net {
25
26namespace internal {
27template <typename ReturnType>
28void ReturnAsParamAdapter(base::OnceCallback<ReturnType()> func,
29 ReturnType* result) {
30 *result = std::move(func).Run();
31}
32
33// Adapts a T* result to a callblack that expects a T.
34template <typename TaskReturnType, typename ReplyArgType>
35void ReplyAdapter(base::OnceCallback<void(ReplyArgType)> callback,
36 TaskReturnType* result) {
37 std::move(callback).Run(std::move(*result));
38}
39} // namespace internal
40
Josh Karlin36985c82018-06-27 15:29:5741// PrioritizedTaskRunner allows for prioritization of posted tasks and their
42// replies. It provides up to 2^32 priority levels. All tasks posted via the
43// PrioritizedTaskRunner will run in priority order. All replies from
44// PostTaskAndReply will also run in priority order. Be careful, as it is
45// possible to starve a task.
Josh Karlindd9a5d142018-06-06 00:35:4846class NET_EXPORT_PRIVATE PrioritizedTaskRunner
47 : public base::RefCountedThreadSafe<PrioritizedTaskRunner> {
48 public:
Josh Karlin36985c82018-06-27 15:29:5749 enum class ReplyRunnerType { kStandard, kPrioritized };
Josh Karlindd9a5d142018-06-06 00:35:4850 PrioritizedTaskRunner(scoped_refptr<base::TaskRunner> task_runner);
51
52 // Similar to TaskRunner::PostTaskAndReply, except that the task runs at
53 // |priority|. Priority 0 is the highest priority and will run before other
54 // priority values. Multiple tasks with the same |priority| value are run in
Josh Karlin36985c82018-06-27 15:29:5755 // order of posting. The replies are also run in prioritized order on the
56 // calling taskrunner.
Josh Karlindd9a5d142018-06-06 00:35:4857 void PostTaskAndReply(const base::Location& from_here,
58 base::OnceClosure task,
59 base::OnceClosure reply,
60 uint32_t priority);
61
62 // Similar to base::PostTaskAndReplyWithResult, except that the task runs at
63 // |priority|. See PostTaskAndReply for a description of |priority|.
64 template <typename TaskReturnType, typename ReplyArgType>
65 void PostTaskAndReplyWithResult(const base::Location& from_here,
66 base::OnceCallback<TaskReturnType()> task,
67 base::OnceCallback<void(ReplyArgType)> reply,
68 uint32_t priority) {
69 TaskReturnType* result = new TaskReturnType();
70 return PostTaskAndReply(
71 from_here,
72 BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
73 std::move(task), result),
74 BindOnce(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
75 std::move(reply), base::Owned(result)),
76 priority);
77 }
78
79 base::TaskRunner* task_runner() { return task_runner_.get(); }
80
81 private:
82 friend class base::RefCountedThreadSafe<PrioritizedTaskRunner>;
83
84 struct Job {
85 Job(const base::Location& from_here,
86 base::OnceClosure task,
87 base::OnceClosure reply,
Josh Karlinae585b62018-06-07 14:27:1688 uint32_t priority,
89 uint32_t task_count);
Josh Karlinead400282018-06-11 18:56:1790 Job();
Josh Karlindd9a5d142018-06-06 00:35:4891 ~Job();
92
93 Job(Job&& other);
94 Job& operator=(Job&& other);
95
96 base::Location from_here;
97 base::OnceClosure task;
98 base::OnceClosure reply;
Josh Karlinead400282018-06-11 18:56:1799 uint32_t priority = 0;
100 uint32_t task_count = 0;
Josh Karlindd9a5d142018-06-06 00:35:48101
102 private:
103 DISALLOW_COPY_AND_ASSIGN(Job);
104 };
105
106 struct JobComparer {
107 bool operator()(const Job& left, const Job& right) {
Josh Karlinae585b62018-06-07 14:27:16108 if (left.priority == right.priority)
109 return left.task_count > right.task_count;
Josh Karlindd9a5d142018-06-06 00:35:48110 return left.priority > right.priority;
111 }
112 };
113
Josh Karlin36985c82018-06-27 15:29:57114 void RunPostTaskAndReply();
115 void RunReply();
Josh Karlindd9a5d142018-06-06 00:35:48116
117 ~PrioritizedTaskRunner();
118
Josh Karlin36985c82018-06-27 15:29:57119 // TODO(jkarlin): Replace the heaps with std::priority_queue once it
Josh Karlindd9a5d142018-06-06 00:35:48120 // supports move-only types.
Josh Karlinead400282018-06-11 18:56:17121 // Accessed on both task_runner_ and the reply task runner.
Josh Karlin36985c82018-06-27 15:29:57122 std::vector<Job> task_job_heap_;
123 base::Lock task_job_heap_lock_;
124 std::vector<Job> reply_job_heap_;
125 base::Lock reply_job_heap_lock_;
Josh Karlindd9a5d142018-06-06 00:35:48126
Josh Karlinead400282018-06-11 18:56:17127 // Accessed on the reply task runner.
Josh Karlindd9a5d142018-06-06 00:35:48128 scoped_refptr<base::TaskRunner> task_runner_;
129
Josh Karlinae585b62018-06-07 14:27:16130 // Used to preserve order of jobs of equal priority. This can overflow and
131 // cause periodic priority inversion. This should be infrequent enough to be
132 // of negligible impact.
133 uint32_t task_count_ = 0;
134
Josh Karlindd9a5d142018-06-06 00:35:48135 DISALLOW_COPY_AND_ASSIGN(PrioritizedTaskRunner);
136};
137
138} // namespace net
139
140#endif // NET_BASE_PRIORITIZED_TASK_RUNNER_H_