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

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: Alternative impl, with scoped_ptr<Callback, DeleteOnCurrentLoop>* Created 5 years, 7 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 | « media/base/BUILD.gn ('k') | media/base/bind_to_current_loop.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"
11 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h" 12 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/single_thread_task_runner.h" 13 #include "base/single_thread_task_runner.h"
14 #include "media/base/media_export.h"
12 15
13 // This is a helper utility for base::Bind()ing callbacks to the current 16 // 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 17 // 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 18 // 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. 19 // when |b| executes the callback, it does so on |a|'s current MessageLoop.
17 // 20 //
18 // Typical usage: request to be called back on the current thread: 21 // Typical usage: request to be called back on the current thread:
19 // other->StartAsyncProcessAndCallMeBack( 22 // other->StartAsyncProcessAndCallMeBack(
20 // media::BindToCurrentLoop(base::Bind(&MyClass::MyMethod, this))); 23 // media::base::BindToCurrentLoop(base::Bind(&MyClass::MyMethod, this)));
danakj 2015/04/29 23:35:01 no base::?
johnme 2015/04/30 16:15:53 Done.
21 // 24 //
22 // Note that like base::Bind(), BindToCurrentLoop() can't bind non-constant 25 // Note that like base::Bind(), BindToCurrentLoop() can't bind non-constant
23 // references, and that *unlike* base::Bind(), BindToCurrentLoop() makes copies 26 // references, and that *unlike* base::Bind(), BindToCurrentLoop() makes copies
24 // of its arguments, and thus can't be used with arrays. 27 // of its arguments, and thus can't be used with arrays.
28 //
29 // The callback passed in to BindToCurrentLoop is guaranteed to be deleted on
30 // the thread from which BindToCurrentLoop was invoked. This allows objects that
31 // must be deleted on the originating thread to be bound into it. In particular,
32 // it can be useful to use WeakPtr<> in the callback so that the reply operation
33 // can be canceled.
25 34
26 namespace media { 35 namespace media {
27 36
37 namespace internal {
38
28 // Mimic base::internal::CallbackForward, replacing p.Pass() with 39 // Mimic base::internal::CallbackForward, replacing p.Pass() with
29 // base::Passed(&p) to account for the extra layer of indirection. 40 // base::Passed(&p) to account for the extra layer of indirection.
30 namespace internal {
31 template <typename T> 41 template <typename T>
32 T& TrampolineForward(T& t) { return t; } 42 T& TrampolineForward(T& t) { return t; }
33 43
34 template <typename T, typename R> 44 template <typename T, typename R>
35 base::internal::PassedWrapper<scoped_ptr<T, R> > TrampolineForward( 45 base::internal::PassedWrapper<scoped_ptr<T, R> > TrampolineForward(
36 scoped_ptr<T, R>& p) { return base::Passed(&p); } 46 scoped_ptr<T, R>& p) { return base::Passed(&p); }
37 47
38 template <typename T> 48 template <typename T>
39 base::internal::PassedWrapper<ScopedVector<T> > TrampolineForward( 49 base::internal::PassedWrapper<ScopedVector<T> > TrampolineForward(
40 ScopedVector<T>& p) { return base::Passed(&p); } 50 ScopedVector<T>& p) { return base::Passed(&p); }
41 51
42 // First, tell the compiler TrampolineHelper is a struct template with one 52 } // namespace internal
43 // type parameter. Then define specializations where the type is a function
44 // returning void and taking zero or more arguments.
45 template <typename Sig> struct TrampolineHelper;
46 53
47 template <typename... Args> 54 // Function object which deletes its parameter, which must be a pointer,
48 struct TrampolineHelper<void(Args...)> { 55 // on the task runner on which this object was constructed.
49 static void Run( 56 //
50 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 57 // This is more expensive than content::BrowserThread::DeleteOnUIThread etc;
51 const base::Callback<void(Args...)>& cb, 58 // use those instead when possible.
52 Args... args) { 59 //
53 task_runner->PostTask(FROM_HERE, 60 // Sample usage with RefCountedThreadSafe:
54 base::Bind(cb, TrampolineForward(args)...)); 61 // class Foo : public base::RefCountedThreadSafe<
62 // Foo, media::base::DeleteOnCurrentLoop> {
63 // ...
64 // private:
65 // friend struct media::base::DeleteOnCurrentLoop;
66 // friend class base::DeleteHelper<Foo>;
67 // ~Foo();
68 // }
69 //
70 // Sample usage with scoped_ptr:
71 // scoped_ptr<Foo, media::base::DeleteOnCurrentLoop> ptr;
danakj 2015/04/29 23:35:01 no base::?
johnme 2015/04/30 16:15:53 Done (ditto above).
72 struct MEDIA_EXPORT DeleteOnCurrentLoop {
danakj 2015/04/29 23:35:01 should this be inside anon/internal?
johnme 2015/04/30 16:15:53 I've moved DeleteOnLoop into internal (a subclass
73 DeleteOnCurrentLoop();
danakj 2015/04/29 23:35:01 i prefer this take a STTR* as an argument instead
johnme 2015/04/30 16:15:53 Done.
74 ~DeleteOnCurrentLoop();
75
76 template <typename T>
77 void operator()(T* ptr) const {
78 enum { type_must_be_complete = sizeof(T) };
79 if (origin_loop_->BelongsToCurrentThread()) {
danakj 2015/04/29 23:37:34 oh and no conditional posting please
johnme 2015/04/30 16:15:53 I modeled this on BrowserThread::DeleteOnThread, w
80 delete ptr;
81 } else {
82 if (!origin_loop_->DeleteSoon(FROM_HERE, ptr)) {
83 #if defined(UNIT_TEST)
84 // Only logged under unit testing because leaks at shutdown
85 // are acceptable under normal circumstances.
86 LOG(ERROR) << "DeleteSoon failed";
danakj 2015/04/29 23:35:01 I'd still prefer LOG(FATAL) and maybe a way to tur
johnme 2015/04/30 16:15:53 Done (hmm ok, I re-read https://codereview.chromiu
87 #endif // UNIT_TEST
88 }
89 }
55 } 90 }
91
92 private:
93 scoped_refptr<base::SingleThreadTaskRunner> origin_loop_;
56 }; 94 };
57 95
58 } // namespace internal 96 namespace {
danakj 2015/04/29 23:35:01 why is this anon but the above is internal?
johnme 2015/04/30 16:15:53 Done (oops, shouldn't use anonymous namespaces in
59 97
60 template<typename T> 98 template<typename... A>
61 static base::Callback<T> BindToCurrentLoop( 99 void PostBackToOriginLoop(
62 const base::Callback<T>& cb) { 100 const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner,
63 return base::Bind(&internal::TrampolineHelper<T>::Run, 101 scoped_ptr<base::Callback<void(A...)>,
64 base::MessageLoopProxy::current(), cb); 102 DeleteOnCurrentLoop>* origin_cb_ptr_ptr,
103 A... args) {
104 origin_task_runner->PostTask(
danakj 2015/04/29 23:35:01 I think that I prefer posting to our own method on
johnme 2015/04/30 16:15:53 We'd still need the custom deleter in case it does
105 FROM_HERE, base::Bind(**origin_cb_ptr_ptr,
106 internal::TrampolineForward(args)...));
107 }
108
109 } // namespace
110
111 template<typename... A>
112 static base::Callback<void(A...)> BindToCurrentLoop(
113 const base::Callback<void(A...)>& origin_cb) {
114 auto cb_copy_ptr = new base::Callback<void(A...)>(origin_cb);
115 // Normally it's pointless to create a scoped_ptr on the heap; here we're just
116 // (ab)using it to take advantage of its custom deleter support.
117 auto cb_copy_ptr_ptr = new scoped_ptr<base::Callback<void(A...)>,
danakj 2015/04/29 23:35:01 can we do this with a scoped_ptr Passed instead of
johnme 2015/04/30 16:15:53 Only allowing the callback to be called once break
118 DeleteOnCurrentLoop>(cb_copy_ptr);
119 return base::Bind(&PostBackToOriginLoop<A...>,
120 base::MessageLoop::current()->task_runner(),
danakj 2015/04/29 23:35:01 ThreadTaskRunnerHandler::Get()?
johnme 2015/04/30 16:15:53 Done (and in .cc).
121 base::Owned(cb_copy_ptr_ptr));
65 } 122 }
66 123
67 } // namespace media 124 } // namespace media
68 125
69 #endif // MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_ 126 #endif // MEDIA_BASE_BIND_TO_CURRENT_LOOP_H_
OLDNEW
« no previous file with comments | « media/base/BUILD.gn ('k') | media/base/bind_to_current_loop.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698