tor-browser

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

ServiceWorkerShutdownBlocker.h (5328B)


      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_serviceworkershutdownblocker_h__
      8 #define mozilla_dom_serviceworkershutdownblocker_h__
      9 
     10 #include "ServiceWorkerShutdownState.h"
     11 #include "mozilla/HashTable.h"
     12 #include "mozilla/InitializedOnce.h"
     13 #include "mozilla/MozPromise.h"
     14 #include "mozilla/NotNull.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsIAsyncShutdown.h"
     17 #include "nsISupportsImpl.h"
     18 #include "nsITimer.h"
     19 
     20 namespace mozilla::dom {
     21 
     22 class ServiceWorkerManager;
     23 
     24 /**
     25 * Main thread only.
     26 *
     27 * A ServiceWorkerShutdownBlocker will "accept promises", and each of these
     28 * promises will be a "pending promise" while it hasn't settled. At some point,
     29 * `StopAcceptingPromises()` should be called and the state will change to "not
     30 * accepting promises" (this is a one way state transition). The shutdown phase
     31 * of the shutdown client the blocker is created with will be blocked until
     32 * there are no more pending promises.
     33 *
     34 * It doesn't matter whether the state changes to "not accepting promises"
     35 * before or during the associated shutdown phase.
     36 *
     37 * In beta/release builds there will be an additional timer that starts ticking
     38 * once both the shutdown phase has been reached and the state is "not accepting
     39 * promises". If when the timer expire there are still pending promises,
     40 * shutdown will be forcefully unblocked.
     41 */
     42 class ServiceWorkerShutdownBlocker final : public nsIAsyncShutdownBlocker,
     43                                           public nsITimerCallback,
     44                                           public nsINamed {
     45 public:
     46  using Progress = ServiceWorkerShutdownState::Progress;
     47  static const uint32_t kInvalidShutdownStateId = 0;
     48 
     49  NS_DECL_ISUPPORTS
     50  NS_DECL_NSIASYNCSHUTDOWNBLOCKER
     51  NS_DECL_NSITIMERCALLBACK
     52  NS_DECL_NSINAMED
     53 
     54  /**
     55   * Returns the registered shutdown blocker if registration succeeded and
     56   * nullptr otherwise.
     57   */
     58  static already_AddRefed<ServiceWorkerShutdownBlocker> CreateAndRegisterOn(
     59      nsIAsyncShutdownClient& aShutdownBarrier,
     60      ServiceWorkerManager& aServiceWorkerManager);
     61 
     62  /**
     63   * Blocks shutdown until `aPromise` settles.
     64   *
     65   * Can be called multiple times, and shutdown will be blocked until all the
     66   * calls' promises settle, but all of these calls must happen before
     67   * `StopAcceptingPromises()` is called (assertions will enforce this).
     68   *
     69   * See `CreateShutdownState` for aShutdownStateId, which is needed to clear
     70   * the shutdown state if the shutdown process aborts for some reason.
     71   */
     72  void WaitOnPromise(GenericNonExclusivePromise* aPromise,
     73                     uint32_t aShutdownStateId);
     74 
     75  /**
     76   * Once this is called, shutdown will be blocked until all promises
     77   * passed to `WaitOnPromise()` settle, and there must be no more calls to
     78   * `WaitOnPromise()` (assertions will enforce this).
     79   */
     80  void StopAcceptingPromises();
     81 
     82  /**
     83   * Start tracking the shutdown of an individual ServiceWorker for hang
     84   * reporting purposes. Returns a "shutdown state ID" that should be used
     85   * in subsequent calls to ReportShutdownProgress. The shutdown of an
     86   * individual ServiceWorker is presumed to be completed when its `Progress`
     87   * reaches `Progress::ShutdownCompleted`.
     88   */
     89  uint32_t CreateShutdownState();
     90 
     91  void ReportShutdownProgress(uint32_t aShutdownStateId, Progress aProgress);
     92 
     93 private:
     94  explicit ServiceWorkerShutdownBlocker(
     95      ServiceWorkerManager& aServiceWorkerManager);
     96 
     97  ~ServiceWorkerShutdownBlocker();
     98 
     99  /**
    100   * No-op if any of the following are true:
    101   * 1) `BlockShutdown()` hasn't been called yet, or
    102   * 2) `StopAcceptingPromises()` hasn't been called yet, or
    103   * 3) `StopAcceptingPromises()` HAS been called, but there are still pending
    104   *    promises.
    105   */
    106  void MaybeUnblockShutdown();
    107 
    108  /**
    109   * Requires `BlockShutdown()` to have been called.
    110   */
    111  void UnblockShutdown();
    112 
    113  /**
    114   * Returns the remaining pending promise count (i.e. excluding the promise
    115   * that just settled).
    116   */
    117  uint32_t PromiseSettled();
    118 
    119  bool IsAcceptingPromises() const;
    120 
    121  uint32_t GetPendingPromises() const;
    122 
    123  /**
    124   * Initializes a timer that will unblock shutdown unconditionally once it's
    125   * expired (even if there are still pending promises). No-op if:
    126   * 1) not a beta or release build, or
    127   * 2) shutdown is not being blocked or `StopAcceptingPromises()` has not been
    128   *    called.
    129   */
    130  void MaybeInitUnblockShutdownTimer();
    131 
    132  struct AcceptingPromises {
    133    uint32_t mPendingPromises = 0;
    134  };
    135 
    136  struct NotAcceptingPromises {
    137    explicit NotAcceptingPromises(AcceptingPromises aPreviousState);
    138 
    139    uint32_t mPendingPromises = 0;
    140  };
    141 
    142  Variant<AcceptingPromises, NotAcceptingPromises> mState;
    143 
    144  nsCOMPtr<nsIAsyncShutdownClient> mShutdownClient;
    145 
    146  HashMap<uint32_t, ServiceWorkerShutdownState> mShutdownStates;
    147 
    148  nsCOMPtr<nsITimer> mTimer;
    149  LazyInitializedOnceEarlyDestructible<
    150      const NotNull<RefPtr<ServiceWorkerManager>>>
    151      mServiceWorkerManager;
    152 };
    153 
    154 }  // namespace mozilla::dom
    155 
    156 #endif  // mozilla_dom_serviceworkershutdownblocker_h__