tor-browser

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

AllocationPolicy.cpp (8398B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 "AllocationPolicy.h"
      8 
      9 #include "ImageContainer.h"
     10 #include "MediaInfo.h"
     11 #include "PDMFactory.h"
     12 #include "mozilla/ClearOnShutdown.h"
     13 #include "mozilla/SchedulerGroup.h"
     14 #ifdef MOZ_WIDGET_ANDROID
     15 #  include "mozilla/jni/Utils.h"
     16 #endif
     17 
     18 namespace mozilla {
     19 
     20 using TrackType = TrackInfo::TrackType;
     21 
     22 class AllocPolicyImpl::AutoDeallocToken : public Token {
     23 public:
     24  explicit AutoDeallocToken(const RefPtr<AllocPolicyImpl>& aPolicy)
     25      : mPolicy(aPolicy) {}
     26 
     27 private:
     28  ~AutoDeallocToken() { mPolicy->Dealloc(); }
     29 
     30  RefPtr<AllocPolicyImpl> mPolicy;
     31 };
     32 
     33 AllocPolicyImpl::AllocPolicyImpl(int aDecoderLimit)
     34    : mMaxDecoderLimit(aDecoderLimit),
     35      mMonitor("AllocPolicyImpl"),
     36      mDecoderLimit(aDecoderLimit) {}
     37 AllocPolicyImpl::~AllocPolicyImpl() { RejectAll(); }
     38 
     39 auto AllocPolicyImpl::Alloc() -> RefPtr<Promise> {
     40  ReentrantMonitorAutoEnter mon(mMonitor);
     41  // No decoder limit set.
     42  if (mDecoderLimit < 0) {
     43    return Promise::CreateAndResolve(new Token(), __func__);
     44  }
     45 
     46  RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
     47  mPromises.push(p);
     48  ResolvePromise(mon);
     49  return p;
     50 }
     51 
     52 void AllocPolicyImpl::Dealloc() {
     53  ReentrantMonitorAutoEnter mon(mMonitor);
     54  ++mDecoderLimit;
     55  ResolvePromise(mon);
     56 }
     57 
     58 void AllocPolicyImpl::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock) {
     59  MOZ_ASSERT(mDecoderLimit >= 0);
     60 
     61  if (mDecoderLimit > 0 && !mPromises.empty()) {
     62    --mDecoderLimit;
     63    RefPtr<PromisePrivate> p = std::move(mPromises.front());
     64    mPromises.pop();
     65    p->Resolve(new AutoDeallocToken(this), __func__);
     66  }
     67 }
     68 
     69 void AllocPolicyImpl::RejectAll() {
     70  ReentrantMonitorAutoEnter mon(mMonitor);
     71  while (!mPromises.empty()) {
     72    RefPtr<PromisePrivate> p = std::move(mPromises.front());
     73    mPromises.pop();
     74    p->Reject(true, __func__);
     75  }
     76 }
     77 
     78 static int32_t MediaDecoderLimitDefault() { return -1; }
     79 
     80 StaticMutex GlobalAllocPolicy::sMutex;
     81 
     82 NotNull<AllocPolicy*> GlobalAllocPolicy::Instance(TrackType aTrack) {
     83  StaticMutexAutoLock lock(sMutex);
     84  if (aTrack == TrackType::kAudioTrack) {
     85    static RefPtr<AllocPolicyImpl> sAudioPolicy = []() {
     86      SchedulerGroup::Dispatch(NS_NewRunnableFunction(
     87          "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() {
     88            ClearOnShutdown(&sAudioPolicy, ShutdownPhase::XPCOMShutdownThreads);
     89          }));
     90      return new AllocPolicyImpl(MediaDecoderLimitDefault());
     91    }();
     92    return WrapNotNull(sAudioPolicy.get());
     93  }
     94  static RefPtr<AllocPolicyImpl> sVideoPolicy = []() {
     95    SchedulerGroup::Dispatch(NS_NewRunnableFunction(
     96        "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() {
     97          ClearOnShutdown(&sVideoPolicy, ShutdownPhase::XPCOMShutdownThreads);
     98        }));
     99    return new AllocPolicyImpl(MediaDecoderLimitDefault());
    100  }();
    101  return WrapNotNull(sVideoPolicy.get());
    102 }
    103 
    104 class SingleAllocPolicy::AutoDeallocCombinedToken : public Token {
    105 public:
    106  AutoDeallocCombinedToken(already_AddRefed<Token> aSingleAllocPolicyToken,
    107                           already_AddRefed<Token> aGlobalAllocPolicyToken)
    108      : mSingleToken(aSingleAllocPolicyToken),
    109        mGlobalToken(aGlobalAllocPolicyToken) {}
    110 
    111 private:
    112  // Release tokens allocated from GlobalAllocPolicy and LocalAllocPolicy
    113  // and process next token request if any.
    114  ~AutoDeallocCombinedToken() = default;
    115  const RefPtr<Token> mSingleToken;
    116  const RefPtr<Token> mGlobalToken;
    117 };
    118 
    119 auto SingleAllocPolicy::Alloc() -> RefPtr<Promise> {
    120  MOZ_DIAGNOSTIC_ASSERT(MaxDecoderLimit() == 1,
    121                        "We can only handle at most one token out at a time.");
    122  RefPtr<SingleAllocPolicy> self = this;
    123  return AllocPolicyImpl::Alloc()->Then(
    124      mOwnerThread, __func__,
    125      [self](RefPtr<Token> aToken) {
    126        RefPtr<Token> localToken = std::move(aToken);
    127        RefPtr<Promise> p = self->mPendingPromise.Ensure(__func__);
    128        GlobalAllocPolicy::Instance(self->mTrack)
    129            ->Alloc()
    130            ->Then(
    131                self->mOwnerThread, __func__,
    132                [self, localToken = std::move(localToken)](
    133                    RefPtr<Token> aToken) mutable {
    134                  self->mTokenRequest.Complete();
    135                  RefPtr<Token> combinedToken = new AutoDeallocCombinedToken(
    136                      localToken.forget(), aToken.forget());
    137                  self->mPendingPromise.Resolve(combinedToken, __func__);
    138                },
    139                [self]() {
    140                  self->mTokenRequest.Complete();
    141                  self->mPendingPromise.Reject(true, __func__);
    142                })
    143            ->Track(self->mTokenRequest);
    144        return p;
    145      },
    146      []() { return Promise::CreateAndReject(true, __func__); });
    147 }
    148 
    149 SingleAllocPolicy::~SingleAllocPolicy() {
    150  mPendingPromise.RejectIfExists(true, __func__);
    151  mTokenRequest.DisconnectIfExists();
    152 }
    153 
    154 void SingleAllocPolicy::Cancel() {
    155  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
    156  mPendingPromise.RejectIfExists(true, __func__);
    157  mTokenRequest.DisconnectIfExists();
    158  RejectAll();
    159 }
    160 
    161 AllocationWrapper::AllocationWrapper(
    162    already_AddRefed<MediaDataDecoder> aDecoder, already_AddRefed<Token> aToken)
    163    : mDecoder(aDecoder), mToken(aToken) {
    164  DecoderDoctorLogger::LogConstructionAndBase(
    165      "AllocationWrapper", this, static_cast<const MediaDataDecoder*>(this));
    166  DecoderDoctorLogger::LinkParentAndChild("AllocationWrapper", this, "decoder",
    167                                          mDecoder.get());
    168 }
    169 
    170 AllocationWrapper::~AllocationWrapper() {
    171  DecoderDoctorLogger::LogDestruction("AllocationWrapper", this);
    172 }
    173 
    174 RefPtr<ShutdownPromise> AllocationWrapper::Shutdown() {
    175  RefPtr<MediaDataDecoder> decoder = std::move(mDecoder);
    176  RefPtr<Token> token = std::move(mToken);
    177  return decoder->Shutdown()->Then(
    178      GetCurrentSerialEventTarget(), __func__,
    179      [token]() { return ShutdownPromise::CreateAndResolve(true, __func__); });
    180 }
    181 /* static */ RefPtr<AllocationWrapper::AllocateDecoderPromise>
    182 AllocationWrapper::CreateDecoder(const CreateDecoderParams& aParams,
    183                                 AllocPolicy* aPolicy) {
    184  RefPtr<AllocateDecoderPromise> p =
    185      (aPolicy ? aPolicy : GlobalAllocPolicy::Instance(aParams.mType))
    186          ->Alloc()
    187          ->Then(
    188              GetCurrentSerialEventTarget(), __func__,
    189              [params =
    190                   CreateDecoderParamsForAsync(aParams)](RefPtr<Token> aToken) {
    191                // result may not always be updated by
    192                // PDMFactory::CreateDecoder either when the creation
    193                // succeeded or failed, as such it must be initialized to a
    194                // fatal error by default.
    195                MediaResult result =
    196                    MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
    197                                nsPrintfCString("error creating %s decoder",
    198                                                TrackTypeToStr(params.mType)));
    199                RefPtr<PDMFactory> pdm = new PDMFactory();
    200                RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
    201                    pdm->CreateDecoder(params)->Then(
    202                        GetCurrentSerialEventTarget(), __func__,
    203                        [aToken](RefPtr<MediaDataDecoder>&& aDecoder) mutable {
    204                          RefPtr<AllocationWrapper> wrapper =
    205                              new AllocationWrapper(aDecoder.forget(),
    206                                                    aToken.forget());
    207                          return AllocateDecoderPromise::CreateAndResolve(
    208                              wrapper, __func__);
    209                        },
    210                        [](const MediaResult& aError) {
    211                          return AllocateDecoderPromise::CreateAndReject(
    212                              aError, __func__);
    213                        });
    214                return p;
    215              },
    216              []() {
    217                return AllocateDecoderPromise::CreateAndReject(
    218                    MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
    219                                "Allocation policy expired"),
    220                    __func__);
    221              });
    222  return p;
    223 }
    224 
    225 }  // namespace mozilla