Index: media/base/state_machine_driver.cc |
diff --git a/media/base/state_machine_driver.cc b/media/base/state_machine_driver.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bc6d717b2013ae3ec31b82159b6dbfac8effe9d8 |
--- /dev/null |
+++ b/media/base/state_machine_driver.cc |
@@ -0,0 +1,79 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/base/state_machine_driver.h" |
+ |
+#include "base/auto_reset.h" |
+#include "base/bind.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+ |
+namespace media { |
+ |
+StateMachineDriver::StateMachineDriver() |
+ : currently_running_(false), |
+ run_posted_(false), |
+ task_runner_(base::ThreadTaskRunnerHandle::Get()), |
+ weak_factory_(this) {} |
+ |
+StateMachineDriver::~StateMachineDriver() {} |
+ |
+void StateMachineDriver::RequestRun(StateMachine* machine) { |
+ // Note that we might, technically, have this machine in |to_run|, which |
+ // would be good enough. as it is, this may schedule a run after that one, |
+ // which is also okay. |
+ machines_to_run_.insert(machine); |
+ |
+ // If we're currently running, then RunAfterPost will notice these machines. |
+ // Otherwise, post RunAfterPost if we haven't already. |
+ if (!currently_running_ && !run_posted_) { |
+ task_runner_->PostTask(FROM_HERE, base::Bind(&StateMachineDriver::RunTask, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ // I suppose that we could RequestRun directly here too, since it's not |
+ // going to be re-entrant. i'm not sure. if two machines are run by |
+ // different drivers, then they might be interleaved, but it's unclear |
+ // if that's okay or not. probably, it doesn't matter, since i'd expect |
+ // every MCVD to have one driver for all its machines, and the state |
+ // wouldn't be shared with other MCVD instances. then again, maybe |
+ // codec allocator state would be shared, or similar. in that case, |
+ // we might have threading issues to worry about too, if the MCVDs |
+ // don't share a common thread. |
+ // It's also not clear if we want RequestRun to ever run things before |
+ // returning, separately from all of that. We might want two variants: |
+ // one that may run immediately, and one that must not. the former |
+ // would be useful for polling media codec, where it would be called |
+ // from a timer. |
+ run_posted_ = true; |
+ } |
+} |
+ |
+void StateMachineDriver::RunImmediately(StateMachine* machine) { |
+ DCHECK(!currently_running_); |
+ |
+ // TODO(liberato): should we cancel any pending post? It doesn't hurt if |
+ // we don't, but we could. |
+ machines_to_run_.insert(machine); |
+ RunTask(); |
+} |
+ |
+void StateMachineDriver::AddStateMachine( |
+ std::unique_ptr<StateMachine> machine) { |
+ machines_.insert(std::move(machine)); |
+ machine->SetOwner(this); |
+} |
+ |
+void StateMachineDriver::RunTask() { |
+ run_posted_ = false; |
+ base::AutoReset<bool> auto_reset(¤tly_running_, true); |
+ |
+ do { |
+ std::unordered_set<StateMachine*> to_run(std::move(machines_to_run_)); |
+ for (StateMachine* machine : to_run) |
+ machine->Run(); |
+ // That might cause more machines to want to run, so keep trying if we |
+ // want to. We can choose to post, too, if we want. |
+ } while (!machines_to_run_.empty()); |
+} |
+ |
+} // namespace media |