tor-browser

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

WorkerTestUtils.cpp (5553B)


      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/WorkerTestUtils.h"
      8 
      9 #include "mozilla/ErrorResult.h"
     10 #include "mozilla/Monitor.h"
     11 #include "mozilla/RefPtr.h"
     12 #include "mozilla/dom/WorkerPrivate.h"
     13 #include "mozilla/dom/WorkerRef.h"
     14 #include "mozilla/dom/WorkerTestUtilsBinding.h"
     15 #include "nsIObserverService.h"
     16 #include "nsThreadUtils.h"
     17 
     18 namespace mozilla::dom {
     19 
     20 uint32_t WorkerTestUtils::CurrentTimerNestingLevel(const GlobalObject& aGlobal,
     21                                                   ErrorResult& aErr) {
     22  MOZ_ASSERT(!NS_IsMainThread());
     23  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     24  MOZ_ASSERT(worker);
     25  return worker->GetCurrentTimerNestingLevel();
     26 }
     27 
     28 bool WorkerTestUtils::IsRunningInBackground(const GlobalObject&,
     29                                            ErrorResult& aErr) {
     30  MOZ_ASSERT(!NS_IsMainThread());
     31  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     32  MOZ_ASSERT(worker);
     33  return worker->IsRunningInBackground();
     34 }
     35 
     36 namespace {
     37 
     38 // Helper for HoldStrongWorkerRefUntilMainThreadObserverNotified that optionally
     39 // holds a ThreadSafeWorkerRef until the given observer notification is notified
     40 // and also notifies a monitor.
     41 class WorkerTestUtilsObserver final : public nsIObserver {
     42 public:
     43  WorkerTestUtilsObserver(const nsACString& aTopic,
     44                          RefPtr<ThreadSafeWorkerRef>&& aWorkerRef)
     45      : mMonitor("WorkerTestUtils"),
     46        mTopic(aTopic),
     47        mWorkerRef(std::move(aWorkerRef)),
     48        mRegistered(false),
     49        mObserved(false) {}
     50 
     51  NS_DECL_THREADSAFE_ISUPPORTS
     52  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
     53                     const char16_t* aData) override {
     54    // We only register for one topic so we don't actually need to compare it.
     55    nsCOMPtr<nsIObserverService> observerService =
     56        services::GetObserverService();
     57    MOZ_ALWAYS_SUCCEEDS(observerService->RemoveObserver(this, mTopic.get()));
     58 
     59    // The ThreadSafeWorkerRef is responsible for / knows how to drop the
     60    // underlying StrongWorkerRef on the worker.
     61    mWorkerRef = nullptr;
     62 
     63    MonitorAutoLock lock(mMonitor);
     64    mObserved = true;
     65    mMonitor.Notify();
     66 
     67    return NS_OK;
     68  }
     69 
     70  void Register() {
     71    nsCOMPtr<nsIObserverService> observerService =
     72        services::GetObserverService();
     73    MOZ_ALWAYS_SUCCEEDS(
     74        observerService->AddObserver(this, mTopic.get(), false));
     75 
     76    MonitorAutoLock lock(mMonitor);
     77    mRegistered = true;
     78    mMonitor.Notify();
     79  }
     80 
     81  void WaitOnRegister() {
     82    MonitorAutoLock lock(mMonitor);
     83    while (!mRegistered) {
     84      mMonitor.Wait();
     85    }
     86  }
     87 
     88  void WaitOnObserver() {
     89    MonitorAutoLock lock(mMonitor);
     90    while (!mObserved) {
     91      mMonitor.Wait();
     92    }
     93  }
     94 
     95 private:
     96  ~WorkerTestUtilsObserver() = default;
     97 
     98  Monitor mMonitor;
     99  nsAutoCString mTopic;
    100  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
    101  bool mRegistered;
    102  bool mObserved;
    103 };
    104 
    105 NS_IMPL_ISUPPORTS(WorkerTestUtilsObserver, nsIObserver)
    106 
    107 }  // anonymous namespace
    108 
    109 void WorkerTestUtils::HoldStrongWorkerRefUntilMainThreadObserverNotified(
    110    const GlobalObject&, const nsACString& aTopic, ErrorResult& aErr) {
    111  MOZ_ASSERT(!NS_IsMainThread());
    112 
    113  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    114  MOZ_ASSERT(workerPrivate);
    115 
    116  RefPtr<StrongWorkerRef> strongWorkerRef =
    117      StrongWorkerRef::Create(workerPrivate, "WorkerTestUtils");
    118  if (NS_WARN_IF(!strongWorkerRef)) {
    119    aErr.Throw(NS_ERROR_FAILURE);
    120    return;
    121  }
    122 
    123  RefPtr<ThreadSafeWorkerRef> tsWorkerRef =
    124      new ThreadSafeWorkerRef(strongWorkerRef);
    125 
    126  auto observer =
    127      MakeRefPtr<WorkerTestUtilsObserver>(aTopic, std::move(tsWorkerRef));
    128 
    129  aErr = NS_DispatchToMainThread(NewRunnableMethod(
    130      "WorkerTestUtils::HoldStrongWorkerRefUntilMainThreadObserverNotified",
    131      observer, &WorkerTestUtilsObserver::Register));
    132 
    133  // Wait for the observer to be registered before returning control so that we
    134  // can be certain we won't miss an observer notification.
    135  observer->WaitOnRegister();
    136 }
    137 
    138 void WorkerTestUtils::BlockUntilMainThreadObserverNotified(
    139    const GlobalObject&, const nsACString& aTopic,
    140    WorkerTestCallback& aWhenObserving, ErrorResult& aErr) {
    141  MOZ_ASSERT(!NS_IsMainThread());
    142 
    143  auto observer = MakeRefPtr<WorkerTestUtilsObserver>(aTopic, nullptr);
    144 
    145  aErr = NS_DispatchToMainThread(
    146      NewRunnableMethod("WorkerTestUtils::BlockUntilMainThreadObserverNotified",
    147                        observer, &WorkerTestUtilsObserver::Register));
    148  if (aErr.Failed()) {
    149    return;
    150  }
    151 
    152  observer->WaitOnRegister();
    153 
    154  aWhenObserving.Call(aErr);
    155  if (aErr.Failed()) {
    156    return;
    157  }
    158 
    159  observer->WaitOnObserver();
    160 }
    161 
    162 void WorkerTestUtils::NotifyObserverOnMainThread(const GlobalObject&,
    163                                                 const nsACString& aTopic,
    164                                                 ErrorResult& aErr) {
    165  MOZ_ASSERT(!NS_IsMainThread());
    166 
    167  aErr = NS_DispatchToMainThread(NS_NewRunnableFunction(
    168      "WorkerTestUtils::NotifyObserverOnMainThread",
    169      [topic = nsCString(aTopic)] {
    170        nsCOMPtr<nsIObserverService> observerService =
    171            services::GetObserverService();
    172        observerService->NotifyObservers(nullptr, topic.get(), nullptr);
    173      }));
    174 }
    175 
    176 }  // namespace mozilla::dom