OLD | NEW |
---|---|
(Empty) | |
1 // 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 | |
10 namespace midi { | |
11 | |
12 namespace { | |
13 | |
14 constexpr TaskService::InstanceId kInvalidInstanceId = -1; | |
15 | |
16 } // namespace | |
17 | |
18 TaskService::TaskService() | |
19 : next_instance_id_(0), bound_instance_id_(kInvalidInstanceId) { | |
20 thread_task_locks_.resize(1); | |
21 thread_task_locks_[0] = base::MakeUnique<base::Lock>(); | |
22 } | |
23 | |
24 TaskService::~TaskService() { | |
25 base::AutoLock lock(lock_); | |
26 threads_.clear(); | |
27 } | |
28 | |
29 bool TaskService::BindInstance() { | |
30 { | |
31 base::AutoLock instance_lock(instance_lock_); | |
32 if (bound_instance_id_ != kInvalidInstanceId) | |
33 return false; | |
34 bound_instance_id_ = next_instance_id_++; | |
35 } | |
36 base::AutoLock lock(lock_); | |
37 DCHECK(!reply_task_runner_); | |
38 reply_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
39 return true; | |
40 } | |
41 | |
42 bool TaskService::UnbindInstance() { | |
43 { | |
44 base::AutoLock instance_lock(instance_lock_); | |
45 if (bound_instance_id_ == kInvalidInstanceId) | |
46 return false; | |
47 bound_instance_id_ = kInvalidInstanceId; | |
48 } | |
49 base::AutoLock lock(lock_); | |
50 DCHECK(reply_task_runner_); | |
51 reply_task_runner_ = nullptr; | |
52 // From now on RunTask will never run any task bound to the instance id. | |
53 // But invoked tasks might be still running here. To ensure no task run before | |
54 // quitting this method, take all |thread_task_locks_| once. | |
55 for (auto& task_lock : thread_task_locks_) | |
56 base::AutoLock auto_task_lock(*task_lock); | |
57 return true; | |
58 } | |
59 | |
60 void TaskService::PostStaticTask(RunnerId runner_id, base::OnceClosure task) { | |
61 scoped_refptr<base::SingleThreadTaskRunner> runner; | |
62 { | |
63 base::AutoLock lock(lock_); | |
64 runner = GetTaskRunner(runner_id); | |
65 } | |
66 runner->PostTask(FROM_HERE, std::move(task)); | |
67 } | |
68 | |
69 void TaskService::PostBoundTask(RunnerId runner_id, base::OnceClosure task) { | |
70 base::AutoLock instance_lock(instance_lock_); | |
71 if (bound_instance_id_ == kInvalidInstanceId) | |
72 return; | |
73 scoped_refptr<base::SingleThreadTaskRunner> runner; | |
74 InstanceId instance_id; | |
75 { | |
76 base::AutoLock lock(lock_); | |
77 runner = GetTaskRunner(runner_id); | |
78 instance_id = bound_instance_id_; | |
79 } | |
80 runner->PostTask(FROM_HERE, | |
81 base::BindOnce(&TaskService::RunTask, base::Unretained(this), | |
82 instance_id, runner_id, std::move(task))); | |
83 } | |
84 | |
85 void TaskService::PostBoundDelayedTask(RunnerId runner_id, | |
86 base::OnceClosure task, | |
87 base::TimeDelta delay) { | |
88 base::AutoLock instance_lock(instance_lock_); | |
89 if (bound_instance_id_ == kInvalidInstanceId) | |
90 return; | |
91 scoped_refptr<base::SingleThreadTaskRunner> runner; | |
92 InstanceId instance_id; | |
93 { | |
94 base::AutoLock lock(lock_); | |
95 runner = GetTaskRunner(runner_id); | |
96 instance_id = bound_instance_id_; | |
97 } | |
98 runner->PostDelayedTask( | |
99 FROM_HERE, | |
100 base::BindOnce(&TaskService::RunTask, base::Unretained(this), instance_id, | |
101 runner_id, std::move(task)), | |
102 delay); | |
103 } | |
104 | |
105 scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner( | |
106 RunnerId runner_id) { | |
107 lock_.AssertAcquired(); | |
108 if (runner_id == kDefaultRunnerId) | |
109 return reply_task_runner_; | |
110 | |
111 DCHECK_EQ(threads_.size() + 1u, thread_task_locks_.size()); | |
yhirano
2017/06/12 07:54:44
You don't need this "+1". Just leaving threads_[0]
Takashi Toyoshima
2017/06/13 06:29:41
sounds a nice idea to keep the code simple.
Done.
| |
112 size_t thread_index = runner_id - 1; | |
113 | |
114 if (threads_.size() <= thread_index) { | |
115 threads_.resize(thread_index + 1); | |
116 thread_task_locks_.resize(runner_id + 1); | |
117 } | |
118 if (!threads_[thread_index]) { | |
119 threads_[thread_index] = base::MakeUnique<base::Thread>(base::StringPrintf( | |
120 "MidiService_TaskService_Thread(%zu)", thread_index)); | |
121 #if defined(OS_WIN) | |
122 threads_[thread_index]->init_com_with_mta(true); | |
123 #endif | |
124 threads_[thread_index]->Start(); | |
125 | |
126 DCHECK(!thread_task_locks_[runner_id]); | |
127 thread_task_locks_[runner_id] = base::MakeUnique<base::Lock>(); | |
128 } | |
129 return threads_[thread_index]->task_runner(); | |
130 } | |
131 | |
132 void TaskService::RunTask(InstanceId instance_id, | |
133 RunnerId runner_id, | |
134 base::OnceClosure task) { | |
135 std::unique_ptr<base::AutoLock> task_lock; | |
136 { | |
137 base::AutoLock instance_lock(instance_lock_); | |
138 // If UnbindInstance() is already called, do nothing. | |
139 if (instance_id != bound_instance_id_) | |
140 return; | |
141 | |
142 // Obtains task lock to ensure that the instance should not complete | |
143 // UnbindInstance() while running the |task|. | |
144 base::AutoLock lock(lock_); | |
145 task_lock = | |
146 base::MakeUnique<base::AutoLock>(*thread_task_locks_[runner_id]); | |
147 } | |
148 std::move(task).Run(); | |
149 } | |
150 | |
151 } // namespace midi | |
OLD | NEW |