summaryrefslogtreecommitdiffstats
path: root/media/mtransport/runnable_utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/mtransport/runnable_utils.h')
-rw-r--r--media/mtransport/runnable_utils.h258
1 files changed, 258 insertions, 0 deletions
diff --git a/media/mtransport/runnable_utils.h b/media/mtransport/runnable_utils.h
new file mode 100644
index 000000000..0d7b1ce6f
--- /dev/null
+++ b/media/mtransport/runnable_utils.h
@@ -0,0 +1,258 @@
+/* -*- 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 "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