tor-browser

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

WorkerRef.cpp (7388B)


      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 #include "mozilla/dom/WorkerRef.h"
      8 
      9 #include "WorkerPrivate.h"
     10 #include "WorkerRunnable.h"
     11 #include "nsDebug.h"
     12 
     13 namespace mozilla::dom {
     14 
     15 namespace {
     16 
     17 // This runnable is used to release the StrongWorkerRef on the worker thread
     18 // when a ThreadSafeWorkerRef is released.
     19 class ReleaseRefControlRunnable final : public WorkerControlRunnable {
     20 public:
     21  ReleaseRefControlRunnable(WorkerPrivate* aWorkerPrivate,
     22                            already_AddRefed<StrongWorkerRef> aRef)
     23      : WorkerControlRunnable("ReleaseRefControlRunnable"),
     24        mRef(std::move(aRef)) {
     25    MOZ_ASSERT(mRef);
     26  }
     27 
     28  bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { return true; }
     29 
     30  void PostDispatch(WorkerPrivate* aWorkerPrivate,
     31                    bool aDispatchResult) override {}
     32 
     33  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
     34    mRef = nullptr;
     35    return true;
     36  }
     37 
     38 private:
     39  RefPtr<StrongWorkerRef> mRef;
     40 };
     41 
     42 }  // namespace
     43 
     44 // ----------------------------------------------------------------------------
     45 // WorkerRef
     46 
     47 WorkerRef::WorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName,
     48                     bool aIsPreventingShutdown)
     49    :
     50 #ifdef DEBUG
     51      mDebugMutex("WorkerRef"),
     52 #endif
     53      mWorkerPrivate(aWorkerPrivate),
     54      mName(aName),
     55      mIsPreventingShutdown(aIsPreventingShutdown),
     56      mHolding(false) {
     57  MOZ_ASSERT(aWorkerPrivate);
     58  MOZ_ASSERT(aName);
     59 
     60  aWorkerPrivate->AssertIsOnWorkerThread();
     61 }
     62 
     63 WorkerRef::~WorkerRef() {
     64  NS_ASSERT_OWNINGTHREAD(WorkerRef);
     65  ReleaseWorker();
     66 }
     67 
     68 void WorkerRef::ReleaseWorker() {
     69  if (mHolding) {
     70    MOZ_ASSERT(mWorkerPrivate);
     71 
     72    if (mIsPreventingShutdown) {
     73      mWorkerPrivate->AssertIsNotPotentiallyLastGCCCRunning();
     74    }
     75    mWorkerPrivate->RemoveWorkerRef(this);
     76    mWorkerPrivate = nullptr;
     77 
     78    mHolding = false;
     79  }
     80 }
     81 
     82 bool WorkerRef::HoldWorker(WorkerStatus aStatus) {
     83  MOZ_ASSERT(mWorkerPrivate);
     84  MOZ_ASSERT(!mHolding);
     85 
     86  if (NS_WARN_IF(!mWorkerPrivate->AddWorkerRef(this, aStatus))) {
     87    return false;
     88  }
     89 
     90  mHolding = true;
     91  return true;
     92 }
     93 
     94 void WorkerRef::Notify() {
     95  NS_ASSERT_OWNINGTHREAD(WorkerRef);
     96 
     97  if (!mCallback) {
     98    return;
     99  }
    100 
    101  MoveOnlyFunction<void()> callback = std::move(mCallback);
    102  MOZ_ASSERT(!mCallback);
    103 
    104  callback();
    105 }
    106 
    107 // ----------------------------------------------------------------------------
    108 // WeakWorkerRef
    109 
    110 /* static */
    111 already_AddRefed<WeakWorkerRef> WeakWorkerRef::Create(
    112    WorkerPrivate* aWorkerPrivate, MoveOnlyFunction<void()>&& aCallback) {
    113  MOZ_ASSERT(aWorkerPrivate);
    114  aWorkerPrivate->AssertIsOnWorkerThread();
    115 
    116  RefPtr<WeakWorkerRef> ref = new WeakWorkerRef(aWorkerPrivate);
    117  if (!ref->HoldWorker(Canceling)) {
    118    return nullptr;
    119  }
    120 
    121  ref->mCallback = std::move(aCallback);
    122 
    123  return ref.forget();
    124 }
    125 
    126 WeakWorkerRef::WeakWorkerRef(WorkerPrivate* aWorkerPrivate)
    127    : WorkerRef(aWorkerPrivate, "WeakWorkerRef", false) {}
    128 
    129 WeakWorkerRef::~WeakWorkerRef() = default;
    130 
    131 void WeakWorkerRef::Notify() {
    132  MOZ_ASSERT(mHolding);
    133  MOZ_ASSERT(mWorkerPrivate);
    134 
    135  // Notify could drop the last reference to this object. We must keep it alive
    136  // in order to call ReleaseWorker() immediately after.
    137  RefPtr<WeakWorkerRef> kungFuGrip = this;
    138 
    139  WorkerRef::Notify();
    140  ReleaseWorker();
    141 }
    142 
    143 WorkerPrivate* WeakWorkerRef::GetPrivate() const {
    144  NS_ASSERT_OWNINGTHREAD(WeakWorkerRef);
    145  return mWorkerPrivate;
    146 }
    147 
    148 WorkerPrivate* WeakWorkerRef::GetUnsafePrivate() const {
    149  return mWorkerPrivate;
    150 }
    151 
    152 // ----------------------------------------------------------------------------
    153 // StrongWorkerRef
    154 
    155 /* static */
    156 already_AddRefed<StrongWorkerRef> StrongWorkerRef::Create(
    157    WorkerPrivate* const aWorkerPrivate, const char* const aName,
    158    MoveOnlyFunction<void()>&& aCallback) {
    159  if (RefPtr<StrongWorkerRef> ref =
    160          CreateImpl(aWorkerPrivate, aName, Canceling)) {
    161    ref->mCallback = std::move(aCallback);
    162    return ref.forget();
    163  }
    164  return nullptr;
    165 }
    166 
    167 /* static */
    168 already_AddRefed<StrongWorkerRef> StrongWorkerRef::CreateForcibly(
    169    WorkerPrivate* const aWorkerPrivate, const char* const aName) {
    170  return CreateImpl(aWorkerPrivate, aName, Killing);
    171 }
    172 
    173 /* static */
    174 already_AddRefed<StrongWorkerRef> StrongWorkerRef::CreateImpl(
    175    WorkerPrivate* const aWorkerPrivate, const char* const aName,
    176    WorkerStatus const aFailStatus) {
    177  MOZ_ASSERT(aWorkerPrivate);
    178  MOZ_ASSERT(aName);
    179 
    180  RefPtr<StrongWorkerRef> ref = new StrongWorkerRef(aWorkerPrivate, aName);
    181  if (!ref->HoldWorker(aFailStatus)) {
    182    return nullptr;
    183  }
    184 
    185  return ref.forget();
    186 }
    187 
    188 StrongWorkerRef::StrongWorkerRef(WorkerPrivate* aWorkerPrivate,
    189                                 const char* aName)
    190    : WorkerRef(aWorkerPrivate, aName, true) {}
    191 
    192 StrongWorkerRef::~StrongWorkerRef() = default;
    193 
    194 WorkerPrivate* StrongWorkerRef::Private() const {
    195  NS_ASSERT_OWNINGTHREAD(StrongWorkerRef);
    196  return mWorkerPrivate;
    197 }
    198 
    199 // ----------------------------------------------------------------------------
    200 // ThreadSafeWorkerRef
    201 
    202 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef* aRef) : mRef(aRef) {
    203  MOZ_ASSERT(aRef);
    204  aRef->Private()->AssertIsOnWorkerThread();
    205 }
    206 
    207 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
    208  // Let's release the StrongWorkerRef on the correct thread.
    209  if (!mRef->mWorkerPrivate->IsOnWorkerThread()) {
    210    WorkerPrivate* workerPrivate = mRef->mWorkerPrivate;
    211    RefPtr<ReleaseRefControlRunnable> r =
    212        new ReleaseRefControlRunnable(workerPrivate, mRef.forget());
    213    r->Dispatch(workerPrivate);
    214    return;
    215  }
    216 }
    217 
    218 WorkerPrivate* ThreadSafeWorkerRef::Private() const {
    219  return mRef->mWorkerPrivate;
    220 }
    221 
    222 // ----------------------------------------------------------------------------
    223 // IPCWorkerRef
    224 
    225 /* static */
    226 already_AddRefed<IPCWorkerRef> IPCWorkerRef::Create(
    227    WorkerPrivate* aWorkerPrivate, const char* aName,
    228    MoveOnlyFunction<void()>&& aCallback) {
    229  MOZ_ASSERT(aWorkerPrivate);
    230  aWorkerPrivate->AssertIsOnWorkerThread();
    231 
    232  RefPtr<IPCWorkerRef> ref = new IPCWorkerRef(aWorkerPrivate, aName);
    233  if (!ref->HoldWorker(Canceling)) {
    234    return nullptr;
    235  }
    236  ref->SetActorCount(1);
    237  ref->mCallback = std::move(aCallback);
    238 
    239  return ref.forget();
    240 }
    241 
    242 IPCWorkerRef::IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName)
    243    : WorkerRef(aWorkerPrivate, aName, false), mActorCount(0) {}
    244 
    245 IPCWorkerRef::~IPCWorkerRef() {
    246  NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
    247  // explicit type convertion to avoid undefined behavior of uint32_t overflow.
    248  mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount(
    249      (int32_t)-mActorCount);
    250  ReleaseWorker();
    251 };
    252 
    253 WorkerPrivate* IPCWorkerRef::Private() const {
    254  NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
    255  return mWorkerPrivate;
    256 }
    257 
    258 void IPCWorkerRef::SetActorCount(uint32_t aCount) {
    259  NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
    260  // explicit type convertion to avoid undefined behavior of uint32_t overflow.
    261  mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount((int32_t)aCount -
    262                                                          (int32_t)mActorCount);
    263  mActorCount = aCount;
    264 }
    265 
    266 }  // namespace mozilla::dom