Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: media/base/bind_to_current_loop.h

Issue 1082113004: BindToCurrentLoop should delete callback on original thread Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | media/base/bind_to_current_loop_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_ 5 #ifndef MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_
6 #define MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_ 6 #define MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_
7 7
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/single_thread_task_runner.h" 12 #include "base/single_thread_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
12 14
13 // This is a helper utility for base::Bind()ing callbacks to the current 15 // This is a helper utility for base::Bind()ing callbacks to the current
14 // MessageLoop. The typical use is when |a| (of class |A|) wants to hand a 16 // MessageLoop. The typical use is when |a| (of class |A|) wants to hand a
15 // callback such as base::Bind(&A::AMethod, a) to |b|, but needs to ensure that 17 // callback such as base::Bind(&A::AMethod, a) to |b|, but needs to ensure that
16 // when |b| executes the callback, it does so on |a|'s current MessageLoop. 18 // when |b| executes the callback, it does so on |a|'s current MessageLoop.
17 // 19 //
18 // Typical usage: request to be called back on the current thread: 20 // Typical usage: request to be called back on the current thread:
19 // other->StartAsyncProcessAndCallMeBack( 21 // other->StartAsyncProcessAndCallMeBack(
20 // media::BindToCurrentLoop(base::Bind(&MyClass::MyMethod, this))); 22 // media::BindToCurrentLoop(base::Bind(&MyClass::MyMethod, this)));
21 // 23 //
22 // Note that like base::Bind(), BindToCurrentLoop() can't bind non-constant 24 // Note that like base::Bind(), BindToCurrentLoop() can't bind non-constant
23 // references, and that *unlike* base::Bind(), BindToCurrentLoop() makes copies 25 // references, and that *unlike* base::Bind(), BindToCurrentLoop() makes copies
24 // of its arguments, and thus can't be used with arrays. 26 // of its arguments, and thus can't be used with arrays.
27 //
28 // The callback passed in to BindToCurrentLoop is guaranteed to be deleted on
29 // the thread from which BindToCurrentLoop was invoked. This allows objects that
30 // must be deleted on the originating thread to be bound into it. In particular,
31 // it can be useful to use WeakPtr<> in the callback so that the reply operation
32 // can be canceled.
25 33
26 namespace media { 34 namespace media {
27 35
36 namespace internal {
37
28 // Mimic base::internal::CallbackForward, replacing p.Pass() with 38 // Mimic base::internal::CallbackForward, replacing p.Pass() with
29 // base::Passed(&p) to account for the extra layer of indirection. 39 // base::Passed(&p) to account for the extra layer of indirection.
30 namespace internal {
31 template <typename T> 40 template <typename T>
32 T& TrampolineForward(T& t) { return t; } 41 T& TrampolineForward(T& t) { return t; }
33 42
34 template <typename T, typename R> 43 template <typename T, typename R>
35 base::internal::PassedWrapper<scoped_ptr<T, R> > TrampolineForward( 44 base::internal::PassedWrapper<scoped_ptr<T, R> > TrampolineForward(
36 scoped_ptr<T, R>& p) { return base::Passed(&p); } 45 scoped_ptr<T, R>& p) { return base::Passed(&p); }
37 46
38 template <typename T> 47 template <typename T>
39 base::internal::PassedWrapper<ScopedVector<T> > TrampolineForward( 48 base::internal::PassedWrapper<ScopedVector<T> > TrampolineForward(
40 ScopedVector<T>& p) { return base::Passed(&p); } 49 ScopedVector<T>& p) { return base::Passed(&p); }
41 50
42 // First, tell the compiler TrampolineHelper is a struct template with one 51 } // namespace internal
43 // type parameter. Then define specializations where the type is a function 52
44 // returning void and taking zero or more arguments. 53 namespace {
45 template <typename Sig> struct TrampolineHelper;
46 54
47 template <typename... Args> 55 template <typename... Args>
48 struct TrampolineHelper<void(Args...)> { 56 class BindToCurrentLoopRelay {
49 static void Run( 57 public:
50 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 58 BindToCurrentLoopRelay(const base::Callback<void(Args...)>& cb)
51 const base::Callback<void(Args...)>& cb, 59 // TODO(johnme): Caller of BindToCurrentLoop should pass in FROM_HERE.
52 Args... args) { 60 : from_here_(FROM_HERE),
53 task_runner->PostTask(FROM_HERE, 61 origin_loop_(base::ThreadTaskRunnerHandle::Get()),
54 base::Bind(cb, TrampolineForward(args)...)); 62 cb_ptr_(new base::Callback<void(Args...)>(cb)) {}
63
64 ~BindToCurrentLoopRelay() {
65 if (origin_loop_->BelongsToCurrentThread()) {
66 delete cb_ptr_;
67 } else if (!origin_loop_->DeleteSoon(from_here_, cb_ptr_)) {
danakj 2015/04/24 19:00:03 I think you want FROM_HERE here? Or why do you use
johnme 2015/04/27 18:32:33 Ok, I've changed both the |from_here_|s to FROM_HE
68 // If DeleteSoon is not possible because the originating MessageLoop is no
69 // longer available, the Callback is leaked. Leaking is considered
70 // preferable to having thread-safety violations caused by invoking the
71 // Callback destructor on the wrong thread.
72 #if defined(UNIT_TEST)
73 // Only logged under unit testing because leaks at shutdown
74 // are acceptable under normal circumstances.
75 LOG(ERROR) << "DeleteSoon failed";
danakj 2015/04/24 19:00:03 FATAL?
johnme 2015/04/27 18:32:33 I copied this from https://codereview.chromium.org
76 #endif // UNIT_TEST
77 }
55 } 78 }
79
80 void Run(Args... args) {
81 // Ignore return value; nothing we can do if PostTask fails.
82 origin_loop_->PostTask(
83 from_here_, base::Bind(*cb_ptr_, internal::TrampolineForward(args)...));
danakj 2015/04/24 19:00:03 Would it be simpler to do this as follows? templa
johnme 2015/04/27 18:32:33 If you delete the callback returned from BindToCur
84 }
85
86 private:
87 tracked_objects::Location from_here_;
88 scoped_refptr<base::SingleThreadTaskRunner> origin_loop_;
89 base::Callback<void(Args...)>* cb_ptr_; // Owned.
56 }; 90 };
57 91
58 } // namespace internal 92 } // namespace
59 93
60 template<typename T> 94 template<typename... Args>
61 static base::Callback<T> BindToCurrentLoop( 95 static base::Callback<void(Args...)> BindToCurrentLoop(
62 const base::Callback<T>& cb) { 96 const base::Callback<void(Args...)>& cb) {
63 return base::Bind(&internal::TrampolineHelper<T>::Run, 97 BindToCurrentLoopRelay<Args...>* relay =
64 base::MessageLoopProxy::current(), cb); 98 new BindToCurrentLoopRelay<Args...>(cb);
99 return base::Bind(&BindToCurrentLoopRelay<Args...>::Run,
100 base::Owned(relay));
65 } 101 }
66 102
67 } // namespace media 103 } // namespace media
68 104
69 #endif // MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_ 105 #endif // MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_
OLDNEW
« no previous file with comments | « no previous file | media/base/bind_to_current_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698