blob: e2a7b573cb454c223c2dd1f200336d848ac3e10a [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
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +00007#include <limits>
8
Sebastien Marchand2912d9f2019-01-25 16:49:37 +00009#include "base/bind.h"
Carlos Caballero2a1dd922019-07-30 14:14:15 +000010#include "base/message_loop/message_pump_type.h"
toyoshimccb8ff92017-06-13 05:31:46 -070011#include "base/strings/stringprintf.h"
Takashi Toyoshima2b92f3b2018-01-09 15:06:22 +090012#include "base/threading/thread_restrictions.h"
toyoshimccb8ff92017-06-13 05:31:46 -070013#include "base/threading/thread_task_runner_handle.h"
Robert Sesek4c4e5e22017-09-26 19:09:25 +000014#include "build/build_config.h"
toyoshimccb8ff92017-06-13 05:31:46 -070015
16namespace midi {
17
Takashi Toyoshima3f0ea8f2018-01-17 09:19:59 +000018constexpr TaskService::RunnerId TaskService::kDefaultRunnerId;
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +000019constexpr TaskService::InstanceId TaskService::kInvalidInstanceId;
Takashi Toyoshima3f0ea8f2018-01-17 09:19:59 +000020
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +000021TaskService::TaskService() : no_tasks_in_flight_cv_(&tasks_in_flight_lock_) {
Robert Liaoa4512b62017-08-29 16:38:28 +000022 DETACH_FROM_SEQUENCE(instance_binding_sequence_checker_);
23}
toyoshimccb8ff92017-06-13 05:31:46 -070024
25TaskService::~TaskService() {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000026 std::vector<std::unique_ptr<base::Thread>> threads;
27 {
28 base::AutoLock lock(lock_);
29 threads = std::move(threads_);
30 DCHECK_EQ(kInvalidInstanceId, bound_instance_id_);
31 }
32 // Should not have any lock to perform thread joins on thread destruction.
33 // All posted tasks should run before quitting the thread message loop.
34 threads.clear();
toyoshimccb8ff92017-06-13 05:31:46 -070035}
36
37bool TaskService::BindInstance() {
Robert Liaoa4512b62017-08-29 16:38:28 +000038 DCHECK_CALLED_ON_VALID_SEQUENCE(instance_binding_sequence_checker_);
toyoshimccb8ff92017-06-13 05:31:46 -070039 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000040 if (bound_instance_id_ != kInvalidInstanceId)
41 return false;
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +000042
43 // If the InstanceId reaches to the limit, just fail rather than doing
44 // something nicer for such impractical case.
45 if (std::numeric_limits<InstanceId>::max() == next_instance_id_)
46 return false;
47
48 bound_instance_id_ = ++next_instance_id_;
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000049
toyoshimccb8ff92017-06-13 05:31:46 -070050 DCHECK(!default_task_runner_);
51 default_task_runner_ = base::ThreadTaskRunnerHandle::Get();
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +000052
toyoshimccb8ff92017-06-13 05:31:46 -070053 return true;
54}
55
56bool TaskService::UnbindInstance() {
Robert Liaoa4512b62017-08-29 16:38:28 +000057 DCHECK_CALLED_ON_VALID_SEQUENCE(instance_binding_sequence_checker_);
toyoshimccb8ff92017-06-13 05:31:46 -070058 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000059 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -070060 if (bound_instance_id_ == kInvalidInstanceId)
61 return false;
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +000062
63 DCHECK_EQ(next_instance_id_, bound_instance_id_);
toyoshimccb8ff92017-06-13 05:31:46 -070064 bound_instance_id_ = kInvalidInstanceId;
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000065
66 DCHECK(default_task_runner_);
67 default_task_runner_ = nullptr;
toyoshimccb8ff92017-06-13 05:31:46 -070068 }
toyoshimccb8ff92017-06-13 05:31:46 -070069 // From now on RunTask will never run any task bound to the instance id.
Robert Liaof66a9cf2017-08-26 01:40:35 +000070 // But invoked tasks might be still running here. To ensure no task runs on
71 // quitting this method, wait for all tasks to complete.
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +000072 base::AutoLock tasks_in_flight_lock(tasks_in_flight_lock_);
Takashi Toyoshima2b92f3b2018-01-09 15:06:22 +090073 // TODO(https://crbug.com/796830): Remove sync operations on the I/O thread.
Raymes Khouryfa472312018-01-15 02:37:35 +000074 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
Robert Liaof66a9cf2017-08-26 01:40:35 +000075 while (tasks_in_flight_ > 0)
76 no_tasks_in_flight_cv_.Wait();
77
toyoshimccb8ff92017-06-13 05:31:46 -070078 return true;
79}
80
Takashi Toyoshima143f0fd2017-08-01 16:15:33 +000081bool TaskService::IsOnTaskRunner(RunnerId runner_id) {
82 base::AutoLock lock(lock_);
83 if (bound_instance_id_ == kInvalidInstanceId)
84 return false;
85
86 if (runner_id == kDefaultRunnerId)
87 return default_task_runner_->BelongsToCurrentThread();
88
89 size_t thread = runner_id - 1;
90 if (threads_.size() <= thread || !threads_[thread])
91 return false;
92
93 return threads_[thread]->task_runner()->BelongsToCurrentThread();
94}
95
toyoshimccb8ff92017-06-13 05:31:46 -070096void TaskService::PostStaticTask(RunnerId runner_id, base::OnceClosure task) {
Takashi Toyoshima3f0ea8f2018-01-17 09:19:59 +000097 DCHECK_NE(kDefaultRunnerId, runner_id);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000098 GetTaskRunner(runner_id)->PostTask(FROM_HERE, std::move(task));
toyoshimccb8ff92017-06-13 05:31:46 -070099}
100
101void TaskService::PostBoundTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -0700102 InstanceId instance_id;
103 {
104 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000105 if (bound_instance_id_ == kInvalidInstanceId)
106 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700107 instance_id = bound_instance_id_;
108 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000109 GetTaskRunner(runner_id)->PostTask(
110 FROM_HERE, base::BindOnce(&TaskService::RunTask, base::Unretained(this),
111 instance_id, runner_id, std::move(task)));
toyoshimccb8ff92017-06-13 05:31:46 -0700112}
113
114void TaskService::PostBoundDelayedTask(RunnerId runner_id,
115 base::OnceClosure task,
116 base::TimeDelta delay) {
toyoshimccb8ff92017-06-13 05:31:46 -0700117 InstanceId instance_id;
118 {
119 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000120 if (bound_instance_id_ == kInvalidInstanceId)
121 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700122 instance_id = bound_instance_id_;
123 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000124 GetTaskRunner(runner_id)->PostDelayedTask(
toyoshimccb8ff92017-06-13 05:31:46 -0700125 FROM_HERE,
126 base::BindOnce(&TaskService::RunTask, base::Unretained(this), instance_id,
127 runner_id, std::move(task)),
128 delay);
129}
130
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +0000131void TaskService::OverflowInstanceIdForTesting() {
132 next_instance_id_ = std::numeric_limits<InstanceId>::max();
133}
134
toyoshimccb8ff92017-06-13 05:31:46 -0700135scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner(
136 RunnerId runner_id) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000137 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700138 if (runner_id == kDefaultRunnerId)
139 return default_task_runner_;
140
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000141 if (threads_.size() < runner_id)
142 threads_.resize(runner_id);
toyoshimccb8ff92017-06-13 05:31:46 -0700143
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000144 size_t thread = runner_id - 1;
145 if (!threads_[thread]) {
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000146 threads_[thread] = std::make_unique<base::Thread>(
toyoshimccb8ff92017-06-13 05:31:46 -0700147 base::StringPrintf("MidiService_TaskService_Thread(%zu)", runner_id));
Robert Sesek4c4e5e22017-09-26 19:09:25 +0000148 base::Thread::Options options;
Xiaohan Wang77cc36d2022-01-15 06:19:37 +0000149#if BUILDFLAG(IS_WIN)
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000150 threads_[thread]->init_com_with_mta(true);
Xiaohan Wang77cc36d2022-01-15 06:19:37 +0000151#elif BUILDFLAG(IS_MAC)
Carlos Caballero2a1dd922019-07-30 14:14:15 +0000152 options.message_pump_type = base::MessagePumpType::UI;
toyoshimccb8ff92017-06-13 05:31:46 -0700153#endif
Olivier Li8d389892021-05-18 04:22:42 +0000154 threads_[thread]->StartWithOptions(std::move(options));
toyoshimccb8ff92017-06-13 05:31:46 -0700155 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000156 return threads_[thread]->task_runner();
toyoshimccb8ff92017-06-13 05:31:46 -0700157}
158
159void TaskService::RunTask(InstanceId instance_id,
160 RunnerId runner_id,
161 base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -0700162 {
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +0000163 base::AutoLock tasks_in_flight_lock(tasks_in_flight_lock_);
Robert Liaof66a9cf2017-08-26 01:40:35 +0000164 ++tasks_in_flight_;
toyoshimccb8ff92017-06-13 05:31:46 -0700165 }
Robert Liaof66a9cf2017-08-26 01:40:35 +0000166
167 if (IsInstanceIdStillBound(instance_id))
168 std::move(task).Run();
169
170 {
Takashi Toyoshima88b4ac02019-02-12 11:25:56 +0000171 base::AutoLock tasks_in_flight_lock(tasks_in_flight_lock_);
Robert Liaof66a9cf2017-08-26 01:40:35 +0000172 --tasks_in_flight_;
173 DCHECK_GE(tasks_in_flight_, 0);
174 if (tasks_in_flight_ == 0)
175 no_tasks_in_flight_cv_.Signal();
176 }
177}
178
179bool TaskService::IsInstanceIdStillBound(InstanceId instance_id) {
180 base::AutoLock lock(lock_);
181 return instance_id == bound_instance_id_;
toyoshimccb8ff92017-06-13 05:31:46 -0700182}
183
184} // namespace midi