1// Copyright (c) 2012 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/base/serial_runner.h" 6 7#include "base/bind.h" 8#include "base/callback_helpers.h" 9#include "base/location.h" 10#include "base/message_loop/message_loop_proxy.h" 11#include "base/single_thread_task_runner.h" 12 13namespace media { 14 15// Converts a Closure into a bound function accepting a PipelineStatusCB. 16static void RunClosure( 17 const base::Closure& closure, 18 const PipelineStatusCB& status_cb) { 19 closure.Run(); 20 status_cb.Run(PIPELINE_OK); 21} 22 23// Converts a bound function accepting a Closure into a bound function 24// accepting a PipelineStatusCB. Since closures have no way of reporting a 25// status |status_cb| is executed with PIPELINE_OK. 26static void RunBoundClosure( 27 const SerialRunner::BoundClosure& bound_closure, 28 const PipelineStatusCB& status_cb) { 29 bound_closure.Run(base::Bind(status_cb, PIPELINE_OK)); 30} 31 32// Runs |status_cb| with |last_status| on |task_runner|. 33static void RunOnTaskRunner( 34 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 35 const PipelineStatusCB& status_cb, 36 PipelineStatus last_status) { 37 // Force post to permit cancellation of a series in the scenario where all 38 // bound functions run on the same thread. 39 task_runner->PostTask(FROM_HERE, base::Bind(status_cb, last_status)); 40} 41 42SerialRunner::Queue::Queue() {} 43SerialRunner::Queue::~Queue() {} 44 45void SerialRunner::Queue::Push(const base::Closure& closure) { 46 bound_fns_.push(base::Bind(&RunClosure, closure)); 47} 48 49void SerialRunner::Queue::Push( 50 const BoundClosure& bound_closure) { 51 bound_fns_.push(base::Bind(&RunBoundClosure, bound_closure)); 52} 53 54void SerialRunner::Queue::Push( 55 const BoundPipelineStatusCB& bound_status_cb) { 56 bound_fns_.push(bound_status_cb); 57} 58 59SerialRunner::BoundPipelineStatusCB SerialRunner::Queue::Pop() { 60 BoundPipelineStatusCB bound_fn = bound_fns_.front(); 61 bound_fns_.pop(); 62 return bound_fn; 63} 64 65bool SerialRunner::Queue::empty() { 66 return bound_fns_.empty(); 67} 68 69SerialRunner::SerialRunner(const Queue& bound_fns, 70 const PipelineStatusCB& done_cb) 71 : task_runner_(base::MessageLoopProxy::current()), 72 bound_fns_(bound_fns), 73 done_cb_(done_cb), 74 weak_factory_(this) { 75 // Respect both cancellation and calling stack guarantees for |done_cb| 76 // when empty. 77 if (bound_fns_.empty()) { 78 task_runner_->PostTask(FROM_HERE, 79 base::Bind(&SerialRunner::RunNextInSeries, 80 weak_factory_.GetWeakPtr(), 81 PIPELINE_OK)); 82 return; 83 } 84 85 RunNextInSeries(PIPELINE_OK); 86} 87 88SerialRunner::~SerialRunner() {} 89 90scoped_ptr<SerialRunner> SerialRunner::Run( 91 const Queue& bound_fns, const PipelineStatusCB& done_cb) { 92 scoped_ptr<SerialRunner> callback_series( 93 new SerialRunner(bound_fns, done_cb)); 94 return callback_series.Pass(); 95} 96 97void SerialRunner::RunNextInSeries(PipelineStatus last_status) { 98 DCHECK(task_runner_->BelongsToCurrentThread()); 99 DCHECK(!done_cb_.is_null()); 100 101 if (bound_fns_.empty() || last_status != PIPELINE_OK) { 102 base::ResetAndReturn(&done_cb_).Run(last_status); 103 return; 104 } 105 106 BoundPipelineStatusCB bound_fn = bound_fns_.Pop(); 107 bound_fn.Run(base::Bind( 108 &RunOnTaskRunner, 109 task_runner_, 110 base::Bind(&SerialRunner::RunNextInSeries, weak_factory_.GetWeakPtr()))); 111} 112 113} // namespace media 114