• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace media {
14 
15 // Converts a Closure into a bound function accepting a PipelineStatusCB.
RunClosure(const base::Closure & closure,const PipelineStatusCB & status_cb)16 static 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.
RunBoundClosure(const SerialRunner::BoundClosure & bound_closure,const PipelineStatusCB & status_cb)26 static 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|.
RunOnTaskRunner(const scoped_refptr<base::SingleThreadTaskRunner> & task_runner,const PipelineStatusCB & status_cb,PipelineStatus last_status)33 static 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 
Queue()42 SerialRunner::Queue::Queue() {}
~Queue()43 SerialRunner::Queue::~Queue() {}
44 
Push(const base::Closure & closure)45 void SerialRunner::Queue::Push(const base::Closure& closure) {
46   bound_fns_.push(base::Bind(&RunClosure, closure));
47 }
48 
Push(const BoundClosure & bound_closure)49 void SerialRunner::Queue::Push(
50     const BoundClosure& bound_closure) {
51   bound_fns_.push(base::Bind(&RunBoundClosure, bound_closure));
52 }
53 
Push(const BoundPipelineStatusCB & bound_status_cb)54 void SerialRunner::Queue::Push(
55     const BoundPipelineStatusCB& bound_status_cb) {
56   bound_fns_.push(bound_status_cb);
57 }
58 
Pop()59 SerialRunner::BoundPipelineStatusCB SerialRunner::Queue::Pop() {
60   BoundPipelineStatusCB bound_fn = bound_fns_.front();
61   bound_fns_.pop();
62   return bound_fn;
63 }
64 
empty()65 bool SerialRunner::Queue::empty() {
66   return bound_fns_.empty();
67 }
68 
SerialRunner(const Queue & bound_fns,const PipelineStatusCB & done_cb)69 SerialRunner::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 
~SerialRunner()88 SerialRunner::~SerialRunner() {}
89 
Run(const Queue & bound_fns,const PipelineStatusCB & done_cb)90 scoped_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 
RunNextInSeries(PipelineStatus last_status)97 void 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