blob: c07b5ff47ee6e041edfa97dd427b288fb5f2fdf1 [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
Gabriel Charette9dc55072017-11-21 20:59:31 +00007#include "base/message_loop/message_loop.h"
toyoshimccb8ff92017-06-13 05:31:46 -07008#include "base/strings/stringprintf.h"
9#include "base/threading/thread_task_runner_handle.h"
Robert Sesek4c4e5e22017-09-26 19:09:25 +000010#include "build/build_config.h"
toyoshimccb8ff92017-06-13 05:31:46 -070011
12namespace midi {
13
14namespace {
15
16constexpr TaskService::InstanceId kInvalidInstanceId = -1;
17
18} // namespace
19
20TaskService::TaskService()
Robert Liaof66a9cf2017-08-26 01:40:35 +000021 : no_tasks_in_flight_cv_(&tasks_in_flight_lock_),
22 tasks_in_flight_(0),
23 next_instance_id_(0),
Robert Liaoa4512b62017-08-29 16:38:28 +000024 bound_instance_id_(kInvalidInstanceId) {
25 DETACH_FROM_SEQUENCE(instance_binding_sequence_checker_);
26}
toyoshimccb8ff92017-06-13 05:31:46 -070027
28TaskService::~TaskService() {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000029 std::vector<std::unique_ptr<base::Thread>> threads;
30 {
31 base::AutoLock lock(lock_);
32 threads = std::move(threads_);
33 DCHECK_EQ(kInvalidInstanceId, bound_instance_id_);
34 }
35 // Should not have any lock to perform thread joins on thread destruction.
36 // All posted tasks should run before quitting the thread message loop.
37 threads.clear();
toyoshimccb8ff92017-06-13 05:31:46 -070038}
39
40bool TaskService::BindInstance() {
Robert Liaoa4512b62017-08-29 16:38:28 +000041 DCHECK_CALLED_ON_VALID_SEQUENCE(instance_binding_sequence_checker_);
toyoshimccb8ff92017-06-13 05:31:46 -070042 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000043 if (bound_instance_id_ != kInvalidInstanceId)
44 return false;
45 bound_instance_id_ = next_instance_id_++;
46
toyoshimccb8ff92017-06-13 05:31:46 -070047 DCHECK(!default_task_runner_);
48 default_task_runner_ = base::ThreadTaskRunnerHandle::Get();
49 return true;
50}
51
52bool TaskService::UnbindInstance() {
Robert Liaoa4512b62017-08-29 16:38:28 +000053 DCHECK_CALLED_ON_VALID_SEQUENCE(instance_binding_sequence_checker_);
toyoshimccb8ff92017-06-13 05:31:46 -070054 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000055 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -070056 if (bound_instance_id_ == kInvalidInstanceId)
57 return false;
58 bound_instance_id_ = kInvalidInstanceId;
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000059
60 DCHECK(default_task_runner_);
61 default_task_runner_ = nullptr;
toyoshimccb8ff92017-06-13 05:31:46 -070062 }
Robert Liaof66a9cf2017-08-26 01:40:35 +000063
toyoshimccb8ff92017-06-13 05:31:46 -070064 // From now on RunTask will never run any task bound to the instance id.
Robert Liaof66a9cf2017-08-26 01:40:35 +000065 // But invoked tasks might be still running here. To ensure no task runs on
66 // quitting this method, wait for all tasks to complete.
67 base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
68 while (tasks_in_flight_ > 0)
69 no_tasks_in_flight_cv_.Wait();
70
toyoshimccb8ff92017-06-13 05:31:46 -070071 return true;
72}
73
Takashi Toyoshima143f0fd2017-08-01 16:15:33 +000074bool TaskService::IsOnTaskRunner(RunnerId runner_id) {
75 base::AutoLock lock(lock_);
76 if (bound_instance_id_ == kInvalidInstanceId)
77 return false;
78
79 if (runner_id == kDefaultRunnerId)
80 return default_task_runner_->BelongsToCurrentThread();
81
82 size_t thread = runner_id - 1;
83 if (threads_.size() <= thread || !threads_[thread])
84 return false;
85
86 return threads_[thread]->task_runner()->BelongsToCurrentThread();
87}
88
toyoshimccb8ff92017-06-13 05:31:46 -070089void TaskService::PostStaticTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -070090 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000091 // Disallow to post a task when no instance is bound, so that new threads
92 // can not be created after the thread finalization in the destructor.
toyoshimccb8ff92017-06-13 05:31:46 -070093 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000094 if (bound_instance_id_ == kInvalidInstanceId)
95 return;
toyoshimccb8ff92017-06-13 05:31:46 -070096 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000097 scoped_refptr<base::SingleThreadTaskRunner> runner;
98 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
131scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner(
132 RunnerId runner_id) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000133 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700134 if (runner_id == kDefaultRunnerId)
135 return default_task_runner_;
136
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000137 if (threads_.size() < runner_id)
138 threads_.resize(runner_id);
toyoshimccb8ff92017-06-13 05:31:46 -0700139
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000140 size_t thread = runner_id - 1;
141 if (!threads_[thread]) {
142 threads_[thread] = base::MakeUnique<base::Thread>(
toyoshimccb8ff92017-06-13 05:31:46 -0700143 base::StringPrintf("MidiService_TaskService_Thread(%zu)", runner_id));
Robert Sesek4c4e5e22017-09-26 19:09:25 +0000144 base::Thread::Options options;
toyoshimccb8ff92017-06-13 05:31:46 -0700145#if defined(OS_WIN)
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000146 threads_[thread]->init_com_with_mta(true);
Robert Sesek4c4e5e22017-09-26 19:09:25 +0000147#elif defined(OS_MACOSX)
148 options.message_loop_type = base::MessageLoop::TYPE_UI;
toyoshimccb8ff92017-06-13 05:31:46 -0700149#endif
Robert Sesek4c4e5e22017-09-26 19:09:25 +0000150 threads_[thread]->StartWithOptions(options);
toyoshimccb8ff92017-06-13 05:31:46 -0700151 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000152 return threads_[thread]->task_runner();
toyoshimccb8ff92017-06-13 05:31:46 -0700153}
154
155void TaskService::RunTask(InstanceId instance_id,
156 RunnerId runner_id,
157 base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -0700158 {
Robert Liaof66a9cf2017-08-26 01:40:35 +0000159 base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
160 ++tasks_in_flight_;
toyoshimccb8ff92017-06-13 05:31:46 -0700161 }
Robert Liaof66a9cf2017-08-26 01:40:35 +0000162
163 if (IsInstanceIdStillBound(instance_id))
164 std::move(task).Run();
165
166 {
167 base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
168 --tasks_in_flight_;
169 DCHECK_GE(tasks_in_flight_, 0);
170 if (tasks_in_flight_ == 0)
171 no_tasks_in_flight_cv_.Signal();
172 }
173}
174
175bool TaskService::IsInstanceIdStillBound(InstanceId instance_id) {
176 base::AutoLock lock(lock_);
177 return instance_id == bound_instance_id_;
toyoshimccb8ff92017-06-13 05:31:46 -0700178}
179
180} // namespace midi