tor-browser

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

IdleSchedulerChild.cpp (4554B)


      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/ipc/IdleSchedulerChild.h"
      8 #include "mozilla/ipc/IdleSchedulerParent.h"
      9 #include "mozilla/ipc/PBackgroundChild.h"
     10 #include "mozilla/Atomics.h"
     11 #include "mozilla/IdlePeriodState.h"
     12 #include "BackgroundChild.h"
     13 
     14 namespace mozilla::ipc {
     15 
     16 static IdleSchedulerChild* sMainThreadIdleScheduler = nullptr;
     17 static bool sIdleSchedulerDestroyed = false;
     18 
     19 IdleSchedulerChild::~IdleSchedulerChild() {
     20  if (sMainThreadIdleScheduler == this) {
     21    sMainThreadIdleScheduler = nullptr;
     22    sIdleSchedulerDestroyed = true;
     23  }
     24  MOZ_ASSERT(!mIdlePeriodState);
     25 }
     26 
     27 void IdleSchedulerChild::Init(IdlePeriodState* aIdlePeriodState) {
     28  mIdlePeriodState = aIdlePeriodState;
     29 
     30  RefPtr<IdleSchedulerChild> scheduler = this;
     31  auto resolve = [&](std::tuple<mozilla::Maybe<MutableSharedMemoryHandle>,
     32                                uint32_t>&& aResult) {
     33    if (auto& handle = std::get<0>(aResult)) {
     34      mActiveCounter = handle->Map();
     35      mChildId = std::get<1>(aResult);
     36      if (mChildId && mIdlePeriodState && mIdlePeriodState->IsActive()) {
     37        SetActive();
     38      }
     39    }
     40  };
     41 
     42  auto reject = [&](ResponseRejectReason) {};
     43  SendInitForIdleUse(std::move(resolve), std::move(reject));
     44 }
     45 
     46 IPCResult IdleSchedulerChild::RecvIdleTime(uint64_t aId, TimeDuration aBudget) {
     47  if (mIdlePeriodState) {
     48    mIdlePeriodState->SetIdleToken(aId, aBudget);
     49  }
     50  return IPC_OK();
     51 }
     52 
     53 void IdleSchedulerChild::SetActive() {
     54  if (mChildId && CanSend() && mActiveCounter) {
     55    auto counters = mActiveCounter.DataAsSpan<Atomic<int32_t>>();
     56    ++counters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
     57    ++counters[mChildId];
     58  }
     59 }
     60 
     61 bool IdleSchedulerChild::SetPaused() {
     62  if (mChildId && CanSend() && mActiveCounter) {
     63    auto counters = mActiveCounter.DataAsSpan<Atomic<int32_t>>();
     64    --counters[mChildId];
     65    // The following expression reduces the global activity count and checks if
     66    // it drops below the cpu counter limit.
     67    return counters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]-- ==
     68           counters[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
     69  }
     70 
     71  return false;
     72 }
     73 
     74 RefPtr<IdleSchedulerChild::MayGCPromise> IdleSchedulerChild::MayGCNow() {
     75  if (mIsRequestingGC || mIsDoingGC) {
     76    return MayGCPromise::CreateAndResolve(false, __func__);
     77  }
     78 
     79  mIsRequestingGC = true;
     80  return SendRequestGC()->Then(
     81      GetMainThreadSerialEventTarget(), __func__,
     82      [self = RefPtr(this)](bool aIgnored) {
     83        // Only one of these may be true at a time.
     84        MOZ_ASSERT(!(self->mIsRequestingGC && self->mIsDoingGC));
     85 
     86        // The parent process always says yes, sometimes after a delay.
     87        if (self->mIsRequestingGC) {
     88          self->mIsRequestingGC = false;
     89          self->mIsDoingGC = true;
     90          return MayGCPromise::CreateAndResolve(true, __func__);
     91        }
     92        return MayGCPromise::CreateAndResolve(false, __func__);
     93      },
     94      [self = RefPtr(this)](ResponseRejectReason reason) {
     95        self->mIsRequestingGC = false;
     96        return MayGCPromise::CreateAndReject(reason, __func__);
     97      });
     98 }
     99 
    100 void IdleSchedulerChild::StartedGC() {
    101  // Only one of these may be true at a time.
    102  MOZ_ASSERT(!(mIsRequestingGC && mIsDoingGC));
    103 
    104  // If mRequestingGC was true then when the outstanding GC request returns
    105  // it'll see that the GC has already started.
    106  mIsRequestingGC = false;
    107 
    108  if (!mIsDoingGC) {
    109    if (CanSend()) {
    110      SendStartedGC();
    111    }
    112    mIsDoingGC = true;
    113  }
    114 }
    115 
    116 void IdleSchedulerChild::DoneGC() {
    117  if (mIsDoingGC) {
    118    if (CanSend()) {
    119      SendDoneGC();
    120    }
    121    mIsDoingGC = false;
    122  }
    123 }
    124 
    125 IdleSchedulerChild* IdleSchedulerChild::GetMainThreadIdleScheduler() {
    126  MOZ_ASSERT(NS_IsMainThread());
    127 
    128  if (sMainThreadIdleScheduler) {
    129    return sMainThreadIdleScheduler;
    130  }
    131 
    132  if (sIdleSchedulerDestroyed) {
    133    return nullptr;
    134  }
    135 
    136  ipc::PBackgroundChild* background =
    137      ipc::BackgroundChild::GetOrCreateForCurrentThread();
    138  if (background) {
    139    // this is nulled out on our destruction, so we don't need to worry
    140    sMainThreadIdleScheduler = new ipc::IdleSchedulerChild();
    141    MOZ_ALWAYS_TRUE(
    142        background->SendPIdleSchedulerConstructor(sMainThreadIdleScheduler));
    143  }
    144  return sMainThreadIdleScheduler;
    145 }
    146 
    147 }  // namespace mozilla::ipc