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