15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/serial_runner.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback_helpers.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/location.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/single_thread_task_runner.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Converts a Closure into a bound function accepting a PipelineStatusCB.
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static void RunClosure(
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Closure& closure,
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const PipelineStatusCB& status_cb) {
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  closure.Run();
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  status_cb.Run(PIPELINE_OK);
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts a bound function accepting a Closure into a bound function
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accepting a PipelineStatusCB. Since closures have no way of reporting a
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// status |status_cb| is executed with PIPELINE_OK.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void RunBoundClosure(
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SerialRunner::BoundClosure& bound_closure,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PipelineStatusCB& status_cb) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bound_closure.Run(base::Bind(status_cb, PIPELINE_OK));
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Runs |status_cb| with |last_status| on |task_runner|.
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static void RunOnTaskRunner(
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PipelineStatusCB& status_cb,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PipelineStatus last_status) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force post to permit cancellation of a series in the scenario where all
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bound functions run on the same thread.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  task_runner->PostTask(FROM_HERE, base::Bind(status_cb, last_status));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SerialRunner::Queue::Queue() {}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SerialRunner::Queue::~Queue() {}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SerialRunner::Queue::Push(const base::Closure& closure) {
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bound_fns_.push(base::Bind(&RunClosure, closure));
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SerialRunner::Queue::Push(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundClosure& bound_closure) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bound_fns_.push(base::Bind(&RunBoundClosure, bound_closure));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SerialRunner::Queue::Push(
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundPipelineStatusCB& bound_status_cb) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bound_fns_.push(bound_status_cb);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SerialRunner::BoundPipelineStatusCB SerialRunner::Queue::Pop() {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BoundPipelineStatusCB bound_fn = bound_fns_.front();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bound_fns_.pop();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bound_fn;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SerialRunner::Queue::empty() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bound_fns_.empty();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)SerialRunner::SerialRunner(const Queue& bound_fns,
7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                           const PipelineStatusCB& done_cb)
7123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    : task_runner_(base::MessageLoopProxy::current()),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bound_fns_(bound_fns),
7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      done_cb_(done_cb),
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      weak_factory_(this) {
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Respect both cancellation and calling stack guarantees for |done_cb|
76424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // when empty.
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (bound_fns_.empty()) {
7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    task_runner_->PostTask(FROM_HERE,
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                           base::Bind(&SerialRunner::RunNextInSeries,
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                      weak_factory_.GetWeakPtr(),
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                      PIPELINE_OK));
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  RunNextInSeries(PIPELINE_OK);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SerialRunner::~SerialRunner() {}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<SerialRunner> SerialRunner::Run(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Queue& bound_fns, const PipelineStatusCB& done_cb) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<SerialRunner> callback_series(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new SerialRunner(bound_fns, done_cb));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return callback_series.Pass();
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SerialRunner::RunNextInSeries(PipelineStatus last_status) {
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(task_runner_->BelongsToCurrentThread());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!done_cb_.is_null());
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bound_fns_.empty() || last_status != PIPELINE_OK) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ResetAndReturn(&done_cb_).Run(last_status);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BoundPipelineStatusCB bound_fn = bound_fns_.Pop();
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  bound_fn.Run(base::Bind(
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      &RunOnTaskRunner,
10923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      task_runner_,
11023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      base::Bind(&SerialRunner::RunNextInSeries, weak_factory_.GetWeakPtr())));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
114