/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ // Original author: ekr@rtfm.com #ifndef runnable_utils_h__ #define runnable_utils_h__ #include #include "mozilla/RefPtr.h" #include "nsThreadUtils.h" #include #include #include // Abstract base class for all of our templates namespace mozilla { namespace detail { enum RunnableResult { NoResult, ReturnsResult }; static inline nsresult RunOnThreadInternal(nsIEventTarget* thread, nsIRunnable* runnable, uint32_t flags) { return thread->Dispatch(runnable, flags); } template class runnable_args_base : public Runnable { public: runnable_args_base() : Runnable("media-runnable_args_base") {} NS_IMETHOD Run() final { MOZ_ASSERT(!mHasRun, "Can only be run once"); RunInternal(); #ifdef DEBUG mHasRun = true; #endif return NS_OK; } protected: virtual void RunInternal() = 0; #ifdef DEBUG bool mHasRun = false; #endif }; } // namespace detail template class runnable_args_func : public detail::runnable_args_base { public: // |explicit| to pacify static analysis when there are no |args|. template explicit runnable_args_func(FunType f, Arguments&&... args) : mFunc(f), mArgs(std::forward(args)...) {} protected: void RunInternal() override { std::apply(std::move(mFunc), std::move(mArgs)); } private: FunType mFunc; std::tuple mArgs; }; template runnable_args_func...>* WrapRunnableNM( FunType f, Args&&... args) { return new runnable_args_func...>( f, std::forward(args)...); } template class runnable_args_func_ret : public detail::runnable_args_base { public: template runnable_args_func_ret(Ret* ret, FunType f, Arguments&&... args) : mReturn(ret), mFunc(f), mArgs(std::forward(args)...) {} protected: void RunInternal() override { *mReturn = std::apply(std::move(mFunc), std::move(mArgs)); } private: Ret* mReturn; FunType mFunc; std::tuple mArgs; }; template runnable_args_func_ret...>* WrapRunnableNMRet( R* ret, FunType f, Args&&... args) { return new runnable_args_func_ret...>( ret, f, std::forward(args)...); } template class runnable_args_memfn : public detail::runnable_args_base { public: template runnable_args_memfn(Class&& obj, M method, Arguments&&... args) : mObj(std::forward(obj)), mMethod(method), mArgs(std::forward(args)...) {} protected: void RunInternal() override { std::apply(std::mem_fn(mMethod), std::tuple_cat(std::tie(mObj), std::move(mArgs))); } private: // For holders such as RefPtr and UniquePtr make sure concrete copy is held // rather than a potential dangling reference. std::decay_t mObj; M mMethod; std::tuple mArgs; }; template runnable_args_memfn...>* WrapRunnable( Class&& obj, M method, Args&&... args) { return new runnable_args_memfn...>( std::forward(obj), method, std::forward(args)...); } template class runnable_args_memfn_ret : public detail::runnable_args_base { public: template runnable_args_memfn_ret(Ret* ret, Class&& obj, M method, Arguments... args) : mReturn(ret), mObj(std::forward(obj)), mMethod(method), mArgs(std::forward(args)...) {} protected: void RunInternal() override { *mReturn = std::apply(std::mem_fn(mMethod), std::tuple_cat(std::tie(mObj), std::move(mArgs))); } private: Ret* mReturn; // For holders such as RefPtr and UniquePtr make sure concrete copy is held // rather than a potential dangling reference. std::decay_t mObj; M mMethod; std::tuple mArgs; }; template runnable_args_memfn_ret...>* WrapRunnableRet( R* ret, Class&& obj, M method, Args&&... args) { return new runnable_args_memfn_ret...>( ret, std::forward(obj), method, std::forward(args)...); } static inline nsresult RUN_ON_THREAD( nsIEventTarget* thread, detail::runnable_args_base* runnable, uint32_t flags) { return detail::RunOnThreadInternal( thread, static_cast(runnable), flags); } static inline nsresult RUN_ON_THREAD( nsIEventTarget* thread, detail::runnable_args_base* runnable) { return NS_DispatchAndSpinEventLoopUntilComplete( "webrtc RUN_ON_THREAD"_ns, thread, do_AddRef(static_cast(runnable))); } #ifdef DEBUG # define ASSERT_ON_THREAD(t) \ do { \ if (t) { \ bool on; \ nsresult rv; \ rv = t->IsOnCurrentThread(&on); \ MOZ_ASSERT(NS_SUCCEEDED(rv)); \ MOZ_ASSERT(on); \ } \ } while (0) #else # define ASSERT_ON_THREAD(t) #endif template class DispatchedRelease : public detail::runnable_args_base { public: explicit DispatchedRelease(already_AddRefed& ref) : ref_(ref) {} protected: void RunInternal() override { ref_ = nullptr; } private: RefPtr ref_; }; template DispatchedRelease* WrapRelease(already_AddRefed&& ref) { return new DispatchedRelease(ref); } } /* namespace mozilla */ #endif