123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 "nsThreadUtils.h"
- #include "mozilla/IndexSequence.h"
- #include "mozilla/Move.h"
- #include "mozilla/RefPtr.h"
- #include "mozilla/Tuple.h"
- // 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)
- {
- nsCOMPtr<nsIRunnable> runnable_ref(runnable);
- if (thread) {
- bool on;
- nsresult rv;
- rv = thread->IsOnCurrentThread(&on);
- // If the target thread has already shut down, we don't want to assert.
- if (rv != NS_ERROR_NOT_INITIALIZED) {
- MOZ_ASSERT(NS_SUCCEEDED(rv));
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- // we're going to destroy the runnable on this thread!
- return rv;
- }
- if (!on) {
- return thread->Dispatch(runnable_ref.forget(), flags);
- }
- }
- return runnable_ref->Run();
- }
- template<RunnableResult result>
- class runnable_args_base : public Runnable {
- public:
- NS_IMETHOD Run() = 0;
- };
- template<typename R>
- struct RunnableFunctionCallHelper
- {
- template<typename FunType, typename... Args, size_t... Indices>
- static R apply(FunType func, Tuple<Args...>& args, IndexSequence<Indices...>)
- {
- return func(Get<Indices>(args)...);
- }
- };
- // A void specialization is needed in the case where the template instantiator
- // knows we don't want to return a value, but we don't know whether the called
- // function returns void or something else.
- template<>
- struct RunnableFunctionCallHelper<void>
- {
- template<typename FunType, typename... Args, size_t... Indices>
- static void apply(FunType func, Tuple<Args...>& args, IndexSequence<Indices...>)
- {
- func(Get<Indices>(args)...);
- }
- };
- template<typename R>
- struct RunnableMethodCallHelper
- {
- template<typename Class, typename M, typename... Args, size_t... Indices>
- static R apply(Class obj, M method, Tuple<Args...>& args, IndexSequence<Indices...>)
- {
- return ((*obj).*method)(Get<Indices>(args)...);
- }
- };
- // A void specialization is needed in the case where the template instantiator
- // knows we don't want to return a value, but we don't know whether the called
- // method returns void or something else.
- template<>
- struct RunnableMethodCallHelper<void>
- {
- template<typename Class, typename M, typename... Args, size_t... Indices>
- static void apply(Class obj, M method, Tuple<Args...>& args, IndexSequence<Indices...>)
- {
- ((*obj).*method)(Get<Indices>(args)...);
- }
- };
- }
- template<typename FunType, typename... Args>
- class runnable_args_func : public detail::runnable_args_base<detail::NoResult>
- {
- public:
- // |explicit| to pacify static analysis when there are no |args|.
- explicit runnable_args_func(FunType f, Args&&... args)
- : mFunc(f), mArgs(Forward<Args>(args)...)
- {}
- NS_IMETHOD Run() {
- detail::RunnableFunctionCallHelper<void>::apply(mFunc, mArgs, typename IndexSequenceFor<Args...>::Type());
- return NS_OK;
- }
- private:
- FunType mFunc;
- Tuple<Args...> mArgs;
- };
- template<typename FunType, typename... Args>
- runnable_args_func<FunType, Args...>*
- WrapRunnableNM(FunType f, Args... args)
- {
- return new runnable_args_func<FunType, Args...>(f, Move(args)...);
- }
- template<typename Ret, typename FunType, typename... Args>
- class runnable_args_func_ret : public detail::runnable_args_base<detail::ReturnsResult>
- {
- public:
- runnable_args_func_ret(Ret* ret, FunType f, Args&&... args)
- : mReturn(ret), mFunc(f), mArgs(Forward<Args>(args)...)
- {}
- NS_IMETHOD Run() {
- *mReturn = detail::RunnableFunctionCallHelper<Ret>::apply(mFunc, mArgs, typename IndexSequenceFor<Args...>::Type());
- return NS_OK;
- }
- private:
- Ret* mReturn;
- FunType mFunc;
- Tuple<Args...> mArgs;
- };
- template<typename R, typename FunType, typename... Args>
- runnable_args_func_ret<R, FunType, Args...>*
- WrapRunnableNMRet(R* ret, FunType f, Args... args)
- {
- return new runnable_args_func_ret<R, FunType, Args...>(ret, f, Move(args)...);
- }
- template<typename Class, typename M, typename... Args>
- class runnable_args_memfn : public detail::runnable_args_base<detail::NoResult>
- {
- public:
- runnable_args_memfn(Class obj, M method, Args&&... args)
- : mObj(obj), mMethod(method), mArgs(Forward<Args>(args)...)
- {}
- NS_IMETHOD Run() {
- detail::RunnableMethodCallHelper<void>::apply(mObj, mMethod, mArgs, typename IndexSequenceFor<Args...>::Type());
- return NS_OK;
- }
- private:
- Class mObj;
- M mMethod;
- Tuple<Args...> mArgs;
- };
- template<typename Class, typename M, typename... Args>
- runnable_args_memfn<Class, M, Args...>*
- WrapRunnable(Class obj, M method, Args... args)
- {
- return new runnable_args_memfn<Class, M, Args...>(obj, method, Move(args)...);
- }
- template<typename Ret, typename Class, typename M, typename... Args>
- class runnable_args_memfn_ret : public detail::runnable_args_base<detail::ReturnsResult>
- {
- public:
- runnable_args_memfn_ret(Ret* ret, Class obj, M method, Args... args)
- : mReturn(ret), mObj(obj), mMethod(method), mArgs(Forward<Args>(args)...)
- {}
- NS_IMETHOD Run() {
- *mReturn = detail::RunnableMethodCallHelper<Ret>::apply(mObj, mMethod, mArgs, typename IndexSequenceFor<Args...>::Type());
- return NS_OK;
- }
- private:
- Ret* mReturn;
- Class mObj;
- M mMethod;
- Tuple<Args...> mArgs;
- };
- template<typename R, typename Class, typename M, typename... Args>
- runnable_args_memfn_ret<R, Class, M, Args...>*
- WrapRunnableRet(R* ret, Class obj, M method, Args... args)
- {
- return new runnable_args_memfn_ret<R, Class, M, Args...>(ret, obj, method, Move(args)...);
- }
- static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base<detail::NoResult> *runnable, uint32_t flags) {
- return detail::RunOnThreadInternal(thread, static_cast<nsIRunnable *>(runnable), flags);
- }
- static inline nsresult
- RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base<detail::ReturnsResult> *runnable)
- {
- return detail::RunOnThreadInternal(thread, static_cast<nsIRunnable *>(runnable), NS_DISPATCH_SYNC);
- }
- #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 T>
- class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> {
- public:
- explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {}
- NS_IMETHOD Run() {
- ref_ = nullptr;
- return NS_OK;
- }
- private:
- RefPtr<T> ref_;
- };
- template <typename T>
- DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref)
- {
- return new DispatchedRelease<T>(ref);
- }
- } /* namespace mozilla */
- #endif
|