tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

runnable_utils.h (6565B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // Original author: ekr@rtfm.com
      8 
      9 #ifndef runnable_utils_h__
     10 #define runnable_utils_h__
     11 
     12 #include <functional>
     13 #include <tuple>
     14 #include <type_traits>
     15 #include <utility>
     16 
     17 #include "mozilla/RefPtr.h"
     18 #include "nsThreadUtils.h"
     19 
     20 // Abstract base class for all of our templates
     21 namespace mozilla {
     22 
     23 namespace detail {
     24 
     25 enum RunnableResult { NoResult, ReturnsResult };
     26 
     27 static inline nsresult RunOnThreadInternal(
     28    nsIEventTarget* thread, nsIRunnable* runnable,
     29    nsIEventTarget::DispatchFlags flags) {
     30  return thread->Dispatch(runnable, flags);
     31 }
     32 
     33 template <RunnableResult result>
     34 class runnable_args_base : public Runnable {
     35 public:
     36  runnable_args_base() : Runnable("media-runnable_args_base") {}
     37 
     38  NS_IMETHOD Run() final {
     39    MOZ_ASSERT(!mHasRun, "Can only be run once");
     40 
     41    RunInternal();
     42 #ifdef DEBUG
     43    mHasRun = true;
     44 #endif
     45 
     46    return NS_OK;
     47  }
     48 
     49 protected:
     50  virtual void RunInternal() = 0;
     51 #ifdef DEBUG
     52  bool mHasRun = false;
     53 #endif
     54 };
     55 
     56 }  // namespace detail
     57 
     58 template <typename FunType, typename... Args>
     59 class runnable_args_func : public detail::runnable_args_base<detail::NoResult> {
     60 public:
     61  // |explicit| to pacify static analysis when there are no |args|.
     62  template <typename... Arguments>
     63  explicit runnable_args_func(FunType f, Arguments&&... args)
     64      : mFunc(f), mArgs(std::forward<Arguments>(args)...) {}
     65 
     66 protected:
     67  void RunInternal() override {
     68    std::apply(std::move(mFunc), std::move(mArgs));
     69  }
     70 
     71 private:
     72  FunType mFunc;
     73  std::tuple<Args...> mArgs;
     74 };
     75 
     76 template <typename FunType, typename... Args>
     77 runnable_args_func<FunType, std::decay_t<Args>...>* WrapRunnableNM(
     78    FunType f, Args&&... args) {
     79  return new runnable_args_func<FunType, std::decay_t<Args>...>(
     80      f, std::forward<Args>(args)...);
     81 }
     82 
     83 template <typename Ret, typename FunType, typename... Args>
     84 class runnable_args_func_ret
     85    : public detail::runnable_args_base<detail::ReturnsResult> {
     86 public:
     87  template <typename... Arguments>
     88  runnable_args_func_ret(Ret* ret, FunType f, Arguments&&... args)
     89      : mReturn(ret), mFunc(f), mArgs(std::forward<Arguments>(args)...) {}
     90 
     91 protected:
     92  void RunInternal() override {
     93    *mReturn = std::apply(std::move(mFunc), std::move(mArgs));
     94  }
     95 
     96 private:
     97  Ret* mReturn;
     98  FunType mFunc;
     99  std::tuple<Args...> mArgs;
    100 };
    101 
    102 template <typename R, typename FunType, typename... Args>
    103 runnable_args_func_ret<R, FunType, std::decay_t<Args>...>* WrapRunnableNMRet(
    104    R* ret, FunType f, Args&&... args) {
    105  return new runnable_args_func_ret<R, FunType, std::decay_t<Args>...>(
    106      ret, f, std::forward<Args>(args)...);
    107 }
    108 
    109 template <typename Class, typename M, typename... Args>
    110 class runnable_args_memfn
    111    : public detail::runnable_args_base<detail::NoResult> {
    112 public:
    113  template <typename... Arguments>
    114  runnable_args_memfn(Class&& obj, M method, Arguments&&... args)
    115      : mObj(std::forward<Class>(obj)),
    116        mMethod(method),
    117        mArgs(std::forward<Arguments>(args)...) {}
    118 
    119 protected:
    120  void RunInternal() override {
    121    std::apply(std::mem_fn(mMethod),
    122               std::tuple_cat(std::tie(mObj), std::move(mArgs)));
    123  }
    124 
    125 private:
    126  // For holders such as RefPtr and UniquePtr make sure concrete copy is held
    127  // rather than a potential dangling reference.
    128  std::decay_t<Class> mObj;
    129  M mMethod;
    130  std::tuple<Args...> mArgs;
    131 };
    132 
    133 template <typename Class, typename M, typename... Args>
    134 runnable_args_memfn<Class, M, std::decay_t<Args>...>* WrapRunnable(
    135    Class&& obj, M method, Args&&... args) {
    136  return new runnable_args_memfn<Class, M, std::decay_t<Args>...>(
    137      std::forward<Class>(obj), method, std::forward<Args>(args)...);
    138 }
    139 
    140 template <typename Ret, typename Class, typename M, typename... Args>
    141 class runnable_args_memfn_ret
    142    : public detail::runnable_args_base<detail::ReturnsResult> {
    143 public:
    144  template <typename... Arguments>
    145  runnable_args_memfn_ret(Ret* ret, Class&& obj, M method, Arguments... args)
    146      : mReturn(ret),
    147        mObj(std::forward<Class>(obj)),
    148        mMethod(method),
    149        mArgs(std::forward<Arguments>(args)...) {}
    150 
    151 protected:
    152  void RunInternal() override {
    153    *mReturn = std::apply(std::mem_fn(mMethod),
    154                          std::tuple_cat(std::tie(mObj), std::move(mArgs)));
    155  }
    156 
    157 private:
    158  Ret* mReturn;
    159  // For holders such as RefPtr and UniquePtr make sure concrete copy is held
    160  // rather than a potential dangling reference.
    161  std::decay_t<Class> mObj;
    162  M mMethod;
    163  std::tuple<Args...> mArgs;
    164 };
    165 
    166 template <typename R, typename Class, typename M, typename... Args>
    167 runnable_args_memfn_ret<R, Class, M, std::decay_t<Args>...>* WrapRunnableRet(
    168    R* ret, Class&& obj, M method, Args&&... args) {
    169  return new runnable_args_memfn_ret<R, Class, M, std::decay_t<Args>...>(
    170      ret, std::forward<Class>(obj), method, std::forward<Args>(args)...);
    171 }
    172 
    173 static inline nsresult RUN_ON_THREAD(
    174    nsIEventTarget* thread,
    175    detail::runnable_args_base<detail::NoResult>* runnable,
    176    nsIEventTarget::DispatchFlags flags) {
    177  return detail::RunOnThreadInternal(
    178      thread, static_cast<nsIRunnable*>(runnable), flags);
    179 }
    180 
    181 static inline nsresult RUN_ON_THREAD(
    182    nsIEventTarget* thread,
    183    detail::runnable_args_base<detail::ReturnsResult>* runnable) {
    184  return NS_DispatchAndSpinEventLoopUntilComplete(
    185      "webrtc RUN_ON_THREAD"_ns, thread,
    186      do_AddRef(static_cast<nsIRunnable*>(runnable)));
    187 }
    188 
    189 #ifdef DEBUG
    190 #  define ASSERT_ON_THREAD(t)           \
    191    do {                                \
    192      if (t) {                          \
    193        bool on;                        \
    194        nsresult rv;                    \
    195        rv = t->IsOnCurrentThread(&on); \
    196        MOZ_ASSERT(NS_SUCCEEDED(rv));   \
    197        MOZ_ASSERT(on);                 \
    198      }                                 \
    199    } while (0)
    200 #else
    201 #  define ASSERT_ON_THREAD(t)
    202 #endif
    203 
    204 template <class T>
    205 class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> {
    206 public:
    207  explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {}
    208 
    209 protected:
    210  void RunInternal() override { ref_ = nullptr; }
    211 
    212 private:
    213  RefPtr<T> ref_;
    214 };
    215 
    216 template <typename T>
    217 DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref) {
    218  return new DispatchedRelease<T>(ref);
    219 }
    220 
    221 } /* namespace mozilla */
    222 
    223 #endif