tor-browser

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

RequestCallbackManager.h (4393B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_RequestCallbackManager_h
      8 #define mozilla_dom_RequestCallbackManager_h
      9 
     10 #include <limits>
     11 
     12 #include "mozilla/RefPtr.h"
     13 #include "nsTArray.h"
     14 #include "nsThreadUtils.h"
     15 
     16 namespace mozilla::dom {
     17 
     18 template <typename RequestCallback>
     19 struct RequestCallbackEntry {
     20  RequestCallbackEntry(RequestCallback& aCallback, uint32_t aHandle)
     21      : mCallback(&aCallback), mHandle(aHandle) {
     22    LogTaskBase<RequestCallback>::LogDispatch(mCallback);
     23  }
     24 
     25  ~RequestCallbackEntry() = default;
     26 
     27  // Comparator operators to allow RemoveElementSorted with an
     28  // integer argument on arrays of RequestCallback
     29  bool operator==(uint32_t aHandle) const { return mHandle == aHandle; }
     30  bool operator<(uint32_t aHandle) const { return mHandle < aHandle; }
     31 
     32  RefPtr<RequestCallback> mCallback;
     33  const uint32_t mHandle;
     34  bool mCancelled = false;
     35 };
     36 
     37 template <typename RequestCallback>
     38 class RequestCallbackManager {
     39 public:
     40  RequestCallbackManager() = default;
     41  ~RequestCallbackManager() = default;
     42 
     43  using CallbackList = nsTArray<RequestCallbackEntry<RequestCallback>>;
     44 
     45  nsresult Schedule(RequestCallback& aCallback, uint32_t* aHandle) {
     46    if (mCallbackCounter == std::numeric_limits<uint32_t>::max()) {
     47      // Can't increment without overflowing; bail out
     48      return NS_ERROR_NOT_AVAILABLE;
     49    }
     50    uint32_t newHandle = ++mCallbackCounter;
     51 
     52    mCallbacks.AppendElement(RequestCallbackEntry(aCallback, newHandle));
     53 
     54    *aHandle = newHandle;
     55    return NS_OK;
     56  }
     57 
     58  bool Cancel(uint32_t aHandle) {
     59    // mCallbacks is stored sorted by handle
     60    if (mCallbacks.RemoveElementSorted(aHandle)) {
     61      return true;
     62    }
     63    for (auto* callbacks : mFiringCallbacksOnStack) {
     64      auto index = callbacks->mList.BinaryIndexOf(aHandle);
     65      if (index != CallbackList::NoIndex) {
     66        callbacks->mList.ElementAt(index).mCancelled = true;
     67      }
     68    }
     69    return false;
     70  }
     71 
     72  bool IsEmpty() const { return mCallbacks.IsEmpty(); }
     73 
     74  // FiringCallbacks takes care of:
     75  //  * Stealing (and thus "freezing") the current callback list, in preparation
     76  //    for firing them.
     77  //  * Registering and unregistering in mFiringCallbacksOnStack, to deal with
     78  //    cancellation of in-flight callbacks in cases like the first callback on
     79  //    the list calling cancelAnimationFrame(secondCallbackId) or so.
     80  // mList is guaranteed not to reallocate once stolen. Instead if a callback is
     81  // cancelled mid-firing, the mCancelled bit is set, see Cancel().
     82  struct MOZ_NON_MEMMOVABLE MOZ_STACK_CLASS FiringCallbacks {
     83    explicit FiringCallbacks(RequestCallbackManager& aManager)
     84        : mManager(aManager) {
     85      mList = std::move(aManager.mCallbacks);
     86      aManager.mFiringCallbacksOnStack.AppendElement(this);
     87    }
     88 
     89    ~FiringCallbacks() {
     90      MOZ_ASSERT(mManager.mFiringCallbacksOnStack.LastElement() == this);
     91      mManager.mFiringCallbacksOnStack.RemoveLastElement();
     92    }
     93 
     94    RequestCallbackManager& mManager;
     95    CallbackList mList;
     96  };
     97 
     98  void Unlink() { mCallbacks.Clear(); }
     99 
    100  void Traverse(nsCycleCollectionTraversalCallback& aCB) {
    101    for (auto& i : mCallbacks) {
    102      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
    103          aCB, "RequestCallbackManager::mCallbacks[i]");
    104      aCB.NoteXPCOMChild(i.mCallback);
    105    }
    106  }
    107 
    108 private:
    109  CallbackList mCallbacks;
    110 
    111  // The current lists of callbacks that are executing. Used to deal with
    112  // cancellation within the same frame. Note this is a list to deal reasonably
    113  // with event loop spinning.
    114  AutoTArray<FiringCallbacks*, 1> mFiringCallbacksOnStack;
    115 
    116  // The current frame request callback handle.
    117  uint32_t mCallbackCounter = 0;
    118 };
    119 
    120 template <class RequestCallback>
    121 inline void ImplCycleCollectionUnlink(
    122    RequestCallbackManager<RequestCallback>& aField) {
    123  aField.Unlink();
    124 }
    125 
    126 template <class RequestCallback>
    127 inline void ImplCycleCollectionTraverse(
    128    nsCycleCollectionTraversalCallback& aCallback,
    129    RequestCallbackManager<RequestCallback>& aField, const char* aName,
    130    uint32_t aFlags) {
    131  aField.Traverse(aCallback);
    132 }
    133 
    134 }  // namespace mozilla::dom
    135 
    136 #endif