blob: 664f309dfd12200864f1acd32cae3c8618866816 [file] [log] [blame]
toyoshimccb8ff92017-06-13 05:31:46 -07001// Copyright 2017 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#include "media/midi/task_service.h"
6
7#include "base/strings/stringprintf.h"
8#include "base/threading/thread_task_runner_handle.h"
9
10namespace midi {
11
12namespace {
13
14constexpr TaskService::InstanceId kInvalidInstanceId = -1;
15
16} // namespace
17
18TaskService::TaskService()
Robert Liaof66a9cf2017-08-26 01:40:35 +000019 : no_tasks_in_flight_cv_(&tasks_in_flight_lock_),
20 tasks_in_flight_(0),
21 next_instance_id_(0),
Robert Liaoa4512b62017-08-29 16:38:28 +000022 bound_instance_id_(kInvalidInstanceId) {
23 DETACH_FROM_SEQUENCE(instance_binding_sequence_checker_);
24}
toyoshimccb8ff92017-06-13 05:31:46 -070025
26TaskService::~TaskService() {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000027 std::vector<std::unique_ptr<base::Thread>> threads;
28 {
29 base::AutoLock lock(lock_);
30 threads = std::move(threads_);
31 DCHECK_EQ(kInvalidInstanceId, bound_instance_id_);
32 }
33 // Should not have any lock to perform thread joins on thread destruction.
34 // All posted tasks should run before quitting the thread message loop.
35 threads.clear();
toyoshimccb8ff92017-06-13 05:31:46 -070036}
37
38bool TaskService::BindInstance() {
Robert Liaoa4512b62017-08-29 16:38:28 +000039 DCHECK_CALLED_ON_VALID_SEQUENCE(instance_binding_sequence_checker_);
toyoshimccb8ff92017-06-13 05:31:46 -070040 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000041 if (bound_instance_id_ != kInvalidInstanceId)
42 return false;
43 bound_instance_id_ = next_instance_id_++;
44
toyoshimccb8ff92017-06-13 05:31:46 -070045 DCHECK(!default_task_runner_);
46 default_task_runner_ = base::ThreadTaskRunnerHandle::Get();
47 return true;
48}
49
50bool TaskService::UnbindInstance() {
Robert Liaoa4512b62017-08-29 16:38:28 +000051 DCHECK_CALLED_ON_VALID_SEQUENCE(instance_binding_sequence_checker_);
toyoshimccb8ff92017-06-13 05:31:46 -070052 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000053 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -070054 if (bound_instance_id_ == kInvalidInstanceId)
55 return false;
56 bound_instance_id_ = kInvalidInstanceId;
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000057
58 DCHECK(default_task_runner_);
59 default_task_runner_ = nullptr;
toyoshimccb8ff92017-06-13 05:31:46 -070060 }
Robert Liaof66a9cf2017-08-26 01:40:35 +000061
toyoshimccb8ff92017-06-13 05:31:46 -070062 // From now on RunTask will never run any task bound to the instance id.
Robert Liaof66a9cf2017-08-26 01:40:35 +000063 // But invoked tasks might be still running here. To ensure no task runs on
64 // quitting this method, wait for all tasks to complete.
65 base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
66 while (tasks_in_flight_ > 0)
67 no_tasks_in_flight_cv_.Wait();
68
toyoshimccb8ff92017-06-13 05:31:46 -070069 return true;
70}
71
Takashi Toyoshima143f0fd2017-08-01 16:15:33 +000072bool TaskService::IsOnTaskRunner(RunnerId runner_id) {
73 base::AutoLock lock(lock_);
74 if (bound_instance_id_ == kInvalidInstanceId)
75 return false;
76
77 if (runner_id == kDefaultRunnerId)
78 return default_task_runner_->BelongsToCurrentThread();
79
80 size_t thread = runner_id - 1;
81 if (threads_.size() <= thread || !threads_[thread])
82 return false;
83
84 return threads_[thread]->task_runner()->BelongsToCurrentThread();
85}
86
toyoshimccb8ff92017-06-13 05:31:46 -070087void TaskService::PostStaticTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -070088 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000089 // Disallow to post a task when no instance is bound, so that new threads
90 // can not be created after the thread finalization in the destructor.
toyoshimccb8ff92017-06-13 05:31:46 -070091 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000092 if (bound_instance_id_ == kInvalidInstanceId)
93 return;
toyoshimccb8ff92017-06-13 05:31:46 -070094 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000095 scoped_refptr<base::SingleThreadTaskRunner> runner;
96 GetTaskRunner(runner_id)->PostTask(FROM_HERE, std::move(task));
toyoshimccb8ff92017-06-13 05:31:46 -070097}
98
99void TaskService::PostBoundTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -0700100 InstanceId instance_id;
101 {
102 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000103 if (bound_instance_id_ == kInvalidInstanceId)
104 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700105 instance_id = bound_instance_id_;
106 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000107 GetTaskRunner(runner_id)->PostTask(
108 FROM_HERE, base::BindOnce(&TaskService::RunTask, base::Unretained(this),
109 instance_id, runner_id, std::move(task)));
toyoshimccb8ff92017-06-13 05:31:46 -0700110}
111
112void TaskService::PostBoundDelayedTask(RunnerId runner_id,
113 base::OnceClosure task,
114 base::TimeDelta delay) {
toyoshimccb8ff92017-06-13 05:31:46 -0700115 InstanceId instance_id;
116 {
117 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000118 if (bound_instance_id_ == kInvalidInstanceId)
119 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700120 instance_id = bound_instance_id_;
121 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000122 GetTaskRunner(runner_id)->PostDelayedTask(
toyoshimccb8ff92017-06-13 05:31:46 -0700123 FROM_HERE,
124 base::BindOnce(&TaskService::RunTask, base::Unretained(this), instance_id,
125 runner_id, std::move(task)),
126 delay);
127}
128
129scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner(
130 RunnerId runner_id) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000131 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700132 if (runner_id == kDefaultRunnerId)
133 return default_task_runner_;
134
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000135 if (threads_.size() < runner_id)
136 threads_.resize(runner_id);
toyoshimccb8ff92017-06-13 05:31:46 -0700137
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000138 size_t thread = runner_id - 1;
139 if (!threads_[thread]) {
140 threads_[thread] = base::MakeUnique<base::Thread>(
toyoshimccb8ff92017-06-13 05:31:46 -0700141 base::StringPrintf("MidiService_TaskService_Thread(%zu)", runner_id));
142#if defined(OS_WIN)
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000143 threads_[thread]->init_com_with_mta(true);
toyoshimccb8ff92017-06-13 05:31:46 -0700144#endif
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000145 threads_[thread]->Start();
toyoshimccb8ff92017-06-13 05:31:46 -0700146 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000147 return threads_[thread]->task_runner();
toyoshimccb8ff92017-06-13 05:31:46 -0700148}
149
150void TaskService::RunTask(InstanceId instance_id,
151 RunnerId runner_id,
152 base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -0700153 {
Robert Liaof66a9cf2017-08-26 01:40:35 +0000154 base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
155 ++tasks_in_flight_;
toyoshimccb8ff92017-06-13 05:31:46 -0700156 }
Robert Liaof66a9cf2017-08-26 01:40:35 +0000157
158 if (IsInstanceIdStillBound(instance_id))
159 std::move(task).Run();
160
161 {
162 base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
163 --tasks_in_flight_;
164 DCHECK_GE(tasks_in_flight_, 0);
165 if (tasks_in_flight_ == 0)
166 no_tasks_in_flight_cv_.Signal();
167 }
168}
169
170bool TaskService::IsInstanceIdStillBound(InstanceId instance_id) {
171 base::AutoLock lock(lock_);
172 return instance_id == bound_instance_id_;
toyoshimccb8ff92017-06-13 05:31:46 -0700173}
174
175} // namespace midi