blob: 2196c7ebee3f62da1074e971780f8fb46f221023 [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()
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000019 : next_instance_id_(0), bound_instance_id_(kInvalidInstanceId) {}
toyoshimccb8ff92017-06-13 05:31:46 -070020
21TaskService::~TaskService() {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000022 std::vector<std::unique_ptr<base::Thread>> threads;
23 {
24 base::AutoLock lock(lock_);
25 threads = std::move(threads_);
26 DCHECK_EQ(kInvalidInstanceId, bound_instance_id_);
27 }
28 // Should not have any lock to perform thread joins on thread destruction.
29 // All posted tasks should run before quitting the thread message loop.
30 threads.clear();
toyoshimccb8ff92017-06-13 05:31:46 -070031}
32
33bool TaskService::BindInstance() {
toyoshimccb8ff92017-06-13 05:31:46 -070034 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000035 if (bound_instance_id_ != kInvalidInstanceId)
36 return false;
37 bound_instance_id_ = next_instance_id_++;
38
toyoshimccb8ff92017-06-13 05:31:46 -070039 DCHECK(!default_task_runner_);
40 default_task_runner_ = base::ThreadTaskRunnerHandle::Get();
41 return true;
42}
43
44bool TaskService::UnbindInstance() {
45 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000046 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -070047 if (bound_instance_id_ == kInvalidInstanceId)
48 return false;
49 bound_instance_id_ = kInvalidInstanceId;
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000050
51 DCHECK(default_task_runner_);
52 default_task_runner_ = nullptr;
toyoshimccb8ff92017-06-13 05:31:46 -070053 }
toyoshimccb8ff92017-06-13 05:31:46 -070054 // From now on RunTask will never run any task bound to the instance id.
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000055 // But invoked tasks might be still running here. To ensure no task run on
56 // quitting this method, take writer lock of |task_lock_|.
57 base::subtle::AutoWriteLock task_lock(task_lock_);
toyoshimccb8ff92017-06-13 05:31:46 -070058 return true;
59}
60
Takashi Toyoshima143f0fd2017-08-01 16:15:33 +000061bool TaskService::IsOnTaskRunner(RunnerId runner_id) {
62 base::AutoLock lock(lock_);
63 if (bound_instance_id_ == kInvalidInstanceId)
64 return false;
65
66 if (runner_id == kDefaultRunnerId)
67 return default_task_runner_->BelongsToCurrentThread();
68
69 size_t thread = runner_id - 1;
70 if (threads_.size() <= thread || !threads_[thread])
71 return false;
72
73 return threads_[thread]->task_runner()->BelongsToCurrentThread();
74}
75
toyoshimccb8ff92017-06-13 05:31:46 -070076void TaskService::PostStaticTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -070077 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000078 // Disallow to post a task when no instance is bound, so that new threads
79 // can not be created after the thread finalization in the destructor.
toyoshimccb8ff92017-06-13 05:31:46 -070080 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000081 if (bound_instance_id_ == kInvalidInstanceId)
82 return;
toyoshimccb8ff92017-06-13 05:31:46 -070083 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000084 scoped_refptr<base::SingleThreadTaskRunner> runner;
85 GetTaskRunner(runner_id)->PostTask(FROM_HERE, std::move(task));
toyoshimccb8ff92017-06-13 05:31:46 -070086}
87
88void TaskService::PostBoundTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -070089 InstanceId instance_id;
90 {
91 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 instance_id = bound_instance_id_;
95 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000096 GetTaskRunner(runner_id)->PostTask(
97 FROM_HERE, base::BindOnce(&TaskService::RunTask, base::Unretained(this),
98 instance_id, runner_id, std::move(task)));
toyoshimccb8ff92017-06-13 05:31:46 -070099}
100
101void TaskService::PostBoundDelayedTask(RunnerId runner_id,
102 base::OnceClosure task,
103 base::TimeDelta delay) {
toyoshimccb8ff92017-06-13 05:31:46 -0700104 InstanceId instance_id;
105 {
106 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000107 if (bound_instance_id_ == kInvalidInstanceId)
108 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700109 instance_id = bound_instance_id_;
110 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000111 GetTaskRunner(runner_id)->PostDelayedTask(
toyoshimccb8ff92017-06-13 05:31:46 -0700112 FROM_HERE,
113 base::BindOnce(&TaskService::RunTask, base::Unretained(this), instance_id,
114 runner_id, std::move(task)),
115 delay);
116}
117
118scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner(
119 RunnerId runner_id) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000120 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700121 if (runner_id == kDefaultRunnerId)
122 return default_task_runner_;
123
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000124 if (threads_.size() < runner_id)
125 threads_.resize(runner_id);
toyoshimccb8ff92017-06-13 05:31:46 -0700126
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000127 size_t thread = runner_id - 1;
128 if (!threads_[thread]) {
129 threads_[thread] = base::MakeUnique<base::Thread>(
toyoshimccb8ff92017-06-13 05:31:46 -0700130 base::StringPrintf("MidiService_TaskService_Thread(%zu)", runner_id));
131#if defined(OS_WIN)
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000132 threads_[thread]->init_com_with_mta(true);
toyoshimccb8ff92017-06-13 05:31:46 -0700133#endif
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000134 threads_[thread]->Start();
toyoshimccb8ff92017-06-13 05:31:46 -0700135 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000136 return threads_[thread]->task_runner();
toyoshimccb8ff92017-06-13 05:31:46 -0700137}
138
139void TaskService::RunTask(InstanceId instance_id,
140 RunnerId runner_id,
141 base::OnceClosure task) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000142 base::subtle::AutoReadLock task_lock(task_lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700143 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000144 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700145 // If UnbindInstance() is already called, do nothing.
146 if (instance_id != bound_instance_id_)
147 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700148 }
149 std::move(task).Run();
150}
151
152} // namespace midi