Index: media/base/bind_to_current_loop.h |
diff --git a/media/base/bind_to_current_loop.h b/media/base/bind_to_current_loop.h |
index cb3e28d4839641f3745684fc7757f87c3aa4cba9..5a57776b1b25ade80e0cab5531dc5e2805e92f0c 100644 |
--- a/media/base/bind_to_current_loop.h |
+++ b/media/base/bind_to_current_loop.h |
@@ -7,8 +7,11 @@ |
#include "base/bind.h" |
#include "base/location.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/message_loop/message_loop.h" |
#include "base/message_loop/message_loop_proxy.h" |
#include "base/single_thread_task_runner.h" |
+#include "media/base/media_export.h" |
// This is a helper utility for base::Bind()ing callbacks to the current |
// MessageLoop. The typical use is when |a| (of class |A|) wants to hand a |
@@ -17,17 +20,24 @@ |
// |
// Typical usage: request to be called back on the current thread: |
// other->StartAsyncProcessAndCallMeBack( |
-// media::BindToCurrentLoop(base::Bind(&MyClass::MyMethod, this))); |
+// 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.
|
// |
// Note that like base::Bind(), BindToCurrentLoop() can't bind non-constant |
// references, and that *unlike* base::Bind(), BindToCurrentLoop() makes copies |
// of its arguments, and thus can't be used with arrays. |
+// |
+// The callback passed in to BindToCurrentLoop is guaranteed to be deleted on |
+// the thread from which BindToCurrentLoop was invoked. This allows objects that |
+// must be deleted on the originating thread to be bound into it. In particular, |
+// it can be useful to use WeakPtr<> in the callback so that the reply operation |
+// can be canceled. |
namespace media { |
+namespace internal { |
+ |
// Mimic base::internal::CallbackForward, replacing p.Pass() with |
// base::Passed(&p) to account for the extra layer of indirection. |
-namespace internal { |
template <typename T> |
T& TrampolineForward(T& t) { return t; } |
@@ -39,29 +49,76 @@ template <typename T> |
base::internal::PassedWrapper<ScopedVector<T> > TrampolineForward( |
ScopedVector<T>& p) { return base::Passed(&p); } |
-// First, tell the compiler TrampolineHelper is a struct template with one |
-// type parameter. Then define specializations where the type is a function |
-// returning void and taking zero or more arguments. |
-template <typename Sig> struct TrampolineHelper; |
- |
-template <typename... Args> |
-struct TrampolineHelper<void(Args...)> { |
- static void Run( |
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
- const base::Callback<void(Args...)>& cb, |
- Args... args) { |
- task_runner->PostTask(FROM_HERE, |
- base::Bind(cb, TrampolineForward(args)...)); |
+} // namespace internal |
+ |
+// Function object which deletes its parameter, which must be a pointer, |
+// on the task runner on which this object was constructed. |
+// |
+// This is more expensive than content::BrowserThread::DeleteOnUIThread etc; |
+// use those instead when possible. |
+// |
+// Sample usage with RefCountedThreadSafe: |
+// class Foo : public base::RefCountedThreadSafe< |
+// Foo, media::base::DeleteOnCurrentLoop> { |
+// ... |
+// private: |
+// friend struct media::base::DeleteOnCurrentLoop; |
+// friend class base::DeleteHelper<Foo>; |
+// ~Foo(); |
+// } |
+// |
+// Sample usage with scoped_ptr: |
+// 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).
|
+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
|
+ 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.
|
+ ~DeleteOnCurrentLoop(); |
+ |
+ template <typename T> |
+ void operator()(T* ptr) const { |
+ enum { type_must_be_complete = sizeof(T) }; |
+ 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
|
+ delete ptr; |
+ } else { |
+ if (!origin_loop_->DeleteSoon(FROM_HERE, ptr)) { |
+#if defined(UNIT_TEST) |
+ // Only logged under unit testing because leaks at shutdown |
+ // are acceptable under normal circumstances. |
+ 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
|
+#endif // UNIT_TEST |
+ } |
+ } |
} |
+ |
+ private: |
+ scoped_refptr<base::SingleThreadTaskRunner> origin_loop_; |
}; |
-} // namespace internal |
+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
|
+ |
+template<typename... A> |
+void PostBackToOriginLoop( |
+ const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner, |
+ scoped_ptr<base::Callback<void(A...)>, |
+ DeleteOnCurrentLoop>* origin_cb_ptr_ptr, |
+ A... args) { |
+ 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
|
+ FROM_HERE, base::Bind(**origin_cb_ptr_ptr, |
+ internal::TrampolineForward(args)...)); |
+} |
+ |
+} // namespace |
-template<typename T> |
-static base::Callback<T> BindToCurrentLoop( |
- const base::Callback<T>& cb) { |
- return base::Bind(&internal::TrampolineHelper<T>::Run, |
- base::MessageLoopProxy::current(), cb); |
+template<typename... A> |
+static base::Callback<void(A...)> BindToCurrentLoop( |
+ const base::Callback<void(A...)>& origin_cb) { |
+ auto cb_copy_ptr = new base::Callback<void(A...)>(origin_cb); |
+ // Normally it's pointless to create a scoped_ptr on the heap; here we're just |
+ // (ab)using it to take advantage of its custom deleter support. |
+ 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
|
+ DeleteOnCurrentLoop>(cb_copy_ptr); |
+ return base::Bind(&PostBackToOriginLoop<A...>, |
+ 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).
|
+ base::Owned(cb_copy_ptr_ptr)); |
} |
} // namespace media |