blob: 188fcf7b72964cbde9b3d91a4ef1dd18c6ad4d38 [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
61void TaskService::PostStaticTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -070062 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000063 // Disallow to post a task when no instance is bound, so that new threads
64 // can not be created after the thread finalization in the destructor.
toyoshimccb8ff92017-06-13 05:31:46 -070065 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000066 if (bound_instance_id_ == kInvalidInstanceId)
67 return;
toyoshimccb8ff92017-06-13 05:31:46 -070068 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000069 scoped_refptr<base::SingleThreadTaskRunner> runner;
70 GetTaskRunner(runner_id)->PostTask(FROM_HERE, std::move(task));
toyoshimccb8ff92017-06-13 05:31:46 -070071}
72
73void TaskService::PostBoundTask(RunnerId runner_id, base::OnceClosure task) {
toyoshimccb8ff92017-06-13 05:31:46 -070074 InstanceId instance_id;
75 {
76 base::AutoLock lock(lock_);
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000077 if (bound_instance_id_ == kInvalidInstanceId)
78 return;
toyoshimccb8ff92017-06-13 05:31:46 -070079 instance_id = bound_instance_id_;
80 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +000081 GetTaskRunner(runner_id)->PostTask(
82 FROM_HERE, base::BindOnce(&TaskService::RunTask, base::Unretained(this),
83 instance_id, runner_id, std::move(task)));
toyoshimccb8ff92017-06-13 05:31:46 -070084}
85
86void TaskService::PostBoundDelayedTask(RunnerId runner_id,
87 base::OnceClosure task,
88 base::TimeDelta delay) {
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)->PostDelayedTask(
toyoshimccb8ff92017-06-13 05:31:46 -070097 FROM_HERE,
98 base::BindOnce(&TaskService::RunTask, base::Unretained(this), instance_id,
99 runner_id, std::move(task)),
100 delay);
101}
102
103scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner(
104 RunnerId runner_id) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000105 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700106 if (runner_id == kDefaultRunnerId)
107 return default_task_runner_;
108
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000109 if (threads_.size() < runner_id)
110 threads_.resize(runner_id);
toyoshimccb8ff92017-06-13 05:31:46 -0700111
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000112 size_t thread = runner_id - 1;
113 if (!threads_[thread]) {
114 threads_[thread] = base::MakeUnique<base::Thread>(
toyoshimccb8ff92017-06-13 05:31:46 -0700115 base::StringPrintf("MidiService_TaskService_Thread(%zu)", runner_id));
116#if defined(OS_WIN)
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000117 threads_[thread]->init_com_with_mta(true);
toyoshimccb8ff92017-06-13 05:31:46 -0700118#endif
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000119 threads_[thread]->Start();
toyoshimccb8ff92017-06-13 05:31:46 -0700120 }
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000121 return threads_[thread]->task_runner();
toyoshimccb8ff92017-06-13 05:31:46 -0700122}
123
124void TaskService::RunTask(InstanceId instance_id,
125 RunnerId runner_id,
126 base::OnceClosure task) {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000127 base::subtle::AutoReadLock task_lock(task_lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700128 {
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000129 base::AutoLock lock(lock_);
toyoshimccb8ff92017-06-13 05:31:46 -0700130 // If UnbindInstance() is already called, do nothing.
131 if (instance_id != bound_instance_id_)
132 return;
toyoshimccb8ff92017-06-13 05:31:46 -0700133 }
134 std::move(task).Run();
135}
136
137} // namespace midi