1 // Copyright 2018 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 #include "net/base/prioritized_task_runner.h"
6
7 #include <algorithm>
8
9 #include "base/functional/bind.h"
10 #include "base/task/task_runner.h"
11 #include "base/task/thread_pool.h"
12
13 namespace net {
14
Job(const base::Location & from_here,base::OnceClosure task,base::OnceClosure reply,uint32_t priority,uint32_t task_count)15 PrioritizedTaskRunner::Job::Job(const base::Location& from_here,
16 base::OnceClosure task,
17 base::OnceClosure reply,
18 uint32_t priority,
19 uint32_t task_count)
20 : from_here(from_here),
21 task(std::move(task)),
22 reply(std::move(reply)),
23 priority(priority),
24 task_count(task_count) {}
25
26 PrioritizedTaskRunner::Job::Job() = default;
27
28 PrioritizedTaskRunner::Job::~Job() = default;
29 PrioritizedTaskRunner::Job::Job(Job&& other) = default;
30 PrioritizedTaskRunner::Job& PrioritizedTaskRunner::Job::operator=(Job&& other) =
31 default;
32
PrioritizedTaskRunner(const base::TaskTraits & task_traits)33 PrioritizedTaskRunner::PrioritizedTaskRunner(
34 const base::TaskTraits& task_traits)
35 : task_traits_(task_traits) {}
36
PostTaskAndReply(const base::Location & from_here,base::OnceClosure task,base::OnceClosure reply,uint32_t priority)37 void PrioritizedTaskRunner::PostTaskAndReply(const base::Location& from_here,
38 base::OnceClosure task,
39 base::OnceClosure reply,
40 uint32_t priority) {
41 Job job(from_here, std::move(task), std::move(reply), priority,
42 task_count_++);
43 task_jobs_.Push(std::move(job));
44
45 scoped_refptr<base::TaskRunner> task_runner;
46 if (task_runner_for_testing_) {
47 task_runner = task_runner_for_testing_;
48 } else {
49 task_runner = base::ThreadPool::CreateSequencedTaskRunner(task_traits_);
50 }
51
52 task_runner->PostTaskAndReply(
53 from_here,
54 base::BindOnce(&PrioritizedTaskRunner::RunTaskAndPostReply, this),
55 base::BindOnce(&PrioritizedTaskRunner::RunReply, this));
56 }
57
58 PrioritizedTaskRunner::~PrioritizedTaskRunner() = default;
59
RunTaskAndPostReply()60 void PrioritizedTaskRunner::RunTaskAndPostReply() {
61 // Find the next job to run.
62 Job job = task_jobs_.Pop();
63
64 std::move(job.task).Run();
65
66 // Add the job to the reply priority queue.
67 reply_jobs_.Push(std::move(job));
68 }
69
RunReply()70 void PrioritizedTaskRunner::RunReply() {
71 // Find the next job to run.
72 Job job = reply_jobs_.Pop();
73
74 // Run the job.
75 std::move(job.reply).Run();
76 }
77
78 struct PrioritizedTaskRunner::JobComparer {
operator ()net::PrioritizedTaskRunner::JobComparer79 bool operator()(const Job& left, const Job& right) {
80 if (left.priority == right.priority) {
81 return left.task_count > right.task_count;
82 }
83 return left.priority > right.priority;
84 }
85 };
86
87 PrioritizedTaskRunner::JobPriorityQueue::JobPriorityQueue() = default;
88 PrioritizedTaskRunner::JobPriorityQueue::~JobPriorityQueue() = default;
89
Push(Job job)90 void PrioritizedTaskRunner::JobPriorityQueue::Push(Job job) {
91 base::AutoLock auto_lock(lock_);
92 heap_.push_back(std::move(job));
93 std::push_heap(heap_.begin(), heap_.end(), JobComparer());
94 }
95
Pop()96 PrioritizedTaskRunner::Job PrioritizedTaskRunner::JobPriorityQueue::Pop() {
97 base::AutoLock auto_lock(lock_);
98 CHECK(!heap_.empty());
99 std::pop_heap(heap_.begin(), heap_.end(), JobComparer());
100 Job job = std::move(heap_.back());
101 heap_.pop_back();
102 return job;
103 }
104
105 } // namespace net
106