| 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 8c14e9e88cd40ad8cec0098f71f2cb53a58b56c2..84a2d7019fb23136636b577661926733fb729929 100644
|
| --- a/media/base/bind_to_current_loop.h
|
| +++ b/media/base/bind_to_current_loop.h
|
| @@ -7,10 +7,12 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/location.h"
|
| +#include "base/memory/ref_counted.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/memory/scoped_vector.h"
|
| #include "base/single_thread_task_runner.h"
|
| #include "base/thread_task_runner_handle.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
|
| @@ -24,12 +26,19 @@
|
| // 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 std::move(p) with
|
| // base::Passed(&p) to account for the extra layer of indirection.
|
| -namespace internal {
|
| template <typename T>
|
| T& TrampolineForward(T& t) { return t; }
|
|
|
| @@ -41,29 +50,86 @@ 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)...));
|
| +// Deleter suitable for use with scoped_ptr (or as traits for
|
| +// RefCountedThreadSafe, if a subclass has a no-arguments constructor).
|
| +struct MEDIA_EXPORT DeleteOnLoop {
|
| + DeleteOnLoop(scoped_refptr<base::SingleThreadTaskRunner> loop);
|
| + ~DeleteOnLoop();
|
| +
|
| + template <typename T>
|
| + void Destruct(const T* ptr) const {
|
| + if (loop_->BelongsToCurrentThread()) {
|
| + delete ptr;
|
| + } else {
|
| + if (!loop_->DeleteSoon(FROM_HERE, ptr)) {
|
| +#if defined(UNIT_TEST)
|
| + // Only logged under unit testing because leaks at shutdown
|
| + // are acceptable under normal circumstances.
|
| + LOG(FATAL) << "DeleteSoon failed";
|
| +#endif // UNIT_TEST
|
| + }
|
| + }
|
| + }
|
| +
|
| + template <typename T>
|
| + inline void operator()(T* ptr) const {
|
| + enum { type_must_be_complete = sizeof(T) };
|
| + Destruct(ptr);
|
| }
|
| +
|
| + private:
|
| + scoped_refptr<base::SingleThreadTaskRunner> loop_;
|
| };
|
|
|
| +template<typename... A>
|
| +void PostBackToOriginLoop(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner,
|
| + scoped_ptr<base::Callback<void(A...)>, DeleteOnLoop>* origin_cb_ptr_ptr,
|
| + A... args) {
|
| + origin_task_runner->PostTask(
|
| + FROM_HERE, base::Bind(**origin_cb_ptr_ptr,
|
| + TrampolineForward(args)...));
|
| +}
|
| +
|
| } // namespace internal
|
|
|
| -template<typename T>
|
| -static base::Callback<T> BindToCurrentLoop(
|
| - const base::Callback<T>& cb) {
|
| - return base::Bind(&internal::TrampolineHelper<T>::Run,
|
| - base::ThreadTaskRunnerHandle::Get(), cb);
|
| +// 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::DeleteOnCurrentLoop> {
|
| +// ...
|
| +// private:
|
| +// friend struct media::DeleteOnCurrentLoop;
|
| +// friend class base::DeleteHelper<Foo>;
|
| +// ~Foo();
|
| +// }
|
| +//
|
| +// Sample usage with scoped_ptr:
|
| +// scoped_ptr<Foo, media::DeleteOnCurrentLoop> ptr;
|
| +struct MEDIA_EXPORT DeleteOnCurrentLoop : internal::DeleteOnLoop {
|
| + DeleteOnCurrentLoop();
|
| + ~DeleteOnCurrentLoop();
|
| +};
|
| +
|
| +template<typename... A>
|
| +static base::Callback<void(A...)> BindToCurrentLoop(
|
| + const base::Callback<void(A...)>& origin_cb) {
|
| + scoped_refptr<base::SingleThreadTaskRunner> loop =
|
| + base::ThreadTaskRunnerHandle::Get();
|
| + 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...)>, internal::DeleteOnLoop>(
|
| + cb_copy_ptr, internal::DeleteOnLoop(loop));
|
| + return base::Bind(&internal::PostBackToOriginLoop<A...>,
|
| + loop,
|
| + base::Owned(cb_copy_ptr_ptr));
|
| }
|
|
|
| } // namespace media
|
|
|