DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/cache/CacheChild.h"

#include "mozilla/Unused.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/cache/Cache.h"
#include "mozilla/dom/cache/CacheOpChild.h"

namespace mozilla {
namespace dom {
namespace cache {

// Declared in ActorUtils.h
PCacheChild* AllocPCacheChild() { return new CacheChild(); }

// Declared in ActorUtils.h
void DeallocPCacheChild(PCacheChild* aActor) { delete aActor; }

CacheChild::CacheChild()
    : mListener(nullptr),
      mNumChildActors(0),
      mDelayedDestroy(false),
      mLocked(false) {
  MOZ_COUNT_CTOR(cache::CacheChild);
}

CacheChild::~CacheChild() {
  MOZ_COUNT_DTOR(cache::CacheChild);
  NS_ASSERT_OWNINGTHREAD(CacheChild);
  MOZ_DIAGNOSTIC_ASSERT(!mListener);
  MOZ_DIAGNOSTIC_ASSERT(!mNumChildActors);
  MOZ_DIAGNOSTIC_ASSERT(!mLocked);
}

void CacheChild::SetListener(Cache* aListener) {
  NS_ASSERT_OWNINGTHREAD(CacheChild);
  MOZ_DIAGNOSTIC_ASSERT(!mListener);
  mListener = aListener;
  MOZ_DIAGNOSTIC_ASSERT(mListener);
}

void CacheChild::ClearListener() {
  NS_ASSERT_OWNINGTHREAD(CacheChild);
  MOZ_DIAGNOSTIC_ASSERT(mListener);
  mListener = nullptr;
}

void CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
                           nsISupports* aParent, const CacheOpArgs& aArgs) {
  mNumChildActors += 1;
  MOZ_ALWAYS_TRUE(SendPCacheOpConstructor(
      new CacheOpChild(GetWorkerHolder(), aGlobal, aParent, aPromise), aArgs));
}

void CacheChild::StartDestroyFromListener() {
  NS_ASSERT_OWNINGTHREAD(CacheChild);

  // The listener should be held alive by any async operations, so if it
  // is going away then there must not be any child actors.  This in turn
  // ensures that StartDestroy() will not trigger the delayed path.
  MOZ_DIAGNOSTIC_ASSERT(!mNumChildActors);

  StartDestroy();
}

void CacheChild::StartDestroy() {
  NS_ASSERT_OWNINGTHREAD(CacheChild);

  // If we have outstanding child actors, then don't destroy ourself yet.
  // The child actors should be short lived and we should allow them to complete
  // if possible.  NoteDeletedActor() will call back into this Shutdown()
  // method when the last child actor is gone.  Also, delay destruction if we
  // have been explicitly locked by someone using us on the stack.
  if (mNumChildActors || mLocked) {
    mDelayedDestroy = true;
    return;
  }

  RefPtr<Cache> listener = mListener;

  // StartDestroy() can get called from either Cache or the WorkerHolder.
  // Theoretically we can get double called if the right race happens.  Handle
  // that by just ignoring the second StartDestroy() call.
  if (!listener) {
    return;
  }

  listener->DestroyInternal(this);

  // Cache listener should call ClearListener() in DestroyInternal()
  MOZ_DIAGNOSTIC_ASSERT(!mListener);

  // Start actor destruction from parent process
  Unused << SendTeardown();
}

void CacheChild::ActorDestroy(ActorDestroyReason aReason) {
  NS_ASSERT_OWNINGTHREAD(CacheChild);
  RefPtr<Cache> listener = mListener;
  if (listener) {
    listener->DestroyInternal(this);
    // Cache listener should call ClearListener() in DestroyInternal()
    MOZ_DIAGNOSTIC_ASSERT(!mListener);
  }

  RemoveWorkerHolder();
}

PCacheOpChild* CacheChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs) {
  MOZ_CRASH("CacheOpChild should be manually constructed.");
  return nullptr;
}

bool CacheChild::DeallocPCacheOpChild(PCacheOpChild* aActor) {
  delete aActor;
  NoteDeletedActor();
  return true;
}

void CacheChild::NoteDeletedActor() {
  mNumChildActors -= 1;
  MaybeFlushDelayedDestroy();
}

void CacheChild::MaybeFlushDelayedDestroy() {
  if (!mNumChildActors && !mLocked && mDelayedDestroy) {
    StartDestroy();
  }
}

void CacheChild::Lock() {
  NS_ASSERT_OWNINGTHREAD(CacheChild);
  MOZ_DIAGNOSTIC_ASSERT(!mLocked);
  mLocked = true;
}

void CacheChild::Unlock() {
  NS_ASSERT_OWNINGTHREAD(CacheChild);
  MOZ_DIAGNOSTIC_ASSERT(mLocked);
  mLocked = false;
  MaybeFlushDelayedDestroy();
}

}  // namespace cache
}  // namespace dom
}  // namespace mozilla