 Chromium Code Reviews
 Chromium Code Reviews Issue 2741713002:
  Web MIDI: implement TaskService  (Closed)
    
  
    Issue 2741713002:
  Web MIDI: implement TaskService  (Closed) 
  | 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 |