Bug 1234458 P1 Allow the CacheChild to be "locked" into memory so it will delay destruction. r=ehsan a=ritu
authorBen Kelly <ben@wanderview.com>
Mon, 04 Jan 2016 12:02:23 -0800
changeset 304177 482240e6ab0da9cf663a33152de7032e30e2cc39
parent 304176 4e8b2e5c39d6171904d136d30922f46fb2b3f5ad
child 304178 de0d8df586dc4eef07d8ad989ea1572a420dc417
push id5453
push userbkelly@mozilla.com
push dateMon, 04 Jan 2016 20:01:56 +0000
treeherdermozilla-beta@de0d8df586dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, ritu
bugs1234458
milestone44.0
Bug 1234458 P1 Allow the CacheChild to be "locked" into memory so it will delay destruction. r=ehsan a=ritu
dom/cache/CacheChild.cpp
dom/cache/CacheChild.h
--- a/dom/cache/CacheChild.cpp
+++ b/dom/cache/CacheChild.cpp
@@ -29,26 +29,28 @@ 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_ASSERT(!mListener);
   MOZ_ASSERT(!mNumChildActors);
+  MOZ_ASSERT(!mLocked);
 }
 
 void
 CacheChild::SetListener(Cache* aListener)
 {
   NS_ASSERT_OWNINGTHREAD(CacheChild);
   MOZ_ASSERT(!mListener);
   mListener = aListener;
@@ -98,18 +100,19 @@ CacheChild::StartDestroyFromListener()
 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.
-  if (mNumChildActors) {
+  // 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 Feature.
   // Theoretically we can get double called if the right race happens.  Handle
@@ -170,16 +173,39 @@ CacheChild::DeallocPCachePushStreamChild
   NoteDeletedActor();
   return true;
 }
 
 void
 CacheChild::NoteDeletedActor()
 {
   mNumChildActors -= 1;
-  if (!mNumChildActors && mDelayedDestroy) {
+  MaybeFlushDelayedDestroy();
+}
+
+void
+CacheChild::MaybeFlushDelayedDestroy()
+{
+  if (!mNumChildActors && !mLocked && mDelayedDestroy) {
     StartDestroy();
   }
 }
 
+void
+CacheChild::Lock()
+{
+  NS_ASSERT_OWNINGTHREAD(CacheChild);
+  MOZ_ASSERT(!mLocked);
+  mLocked = true;
+}
+
+void
+CacheChild::Unlock()
+{
+  NS_ASSERT_OWNINGTHREAD(CacheChild);
+  MOZ_ASSERT(mLocked);
+  mLocked = false;
+  MaybeFlushDelayedDestroy();
+}
+
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/CacheChild.h
+++ b/dom/cache/CacheChild.h
@@ -23,16 +23,34 @@ namespace cache {
 class Cache;
 class CacheOpArgs;
 class CachePushStreamChild;
 
 class CacheChild final : public PCacheChild
                        , public ActorChild
 {
 public:
+  class MOZ_RAII AutoLock final
+  {
+    CacheChild* mActor;
+
+  public:
+    explicit AutoLock(CacheChild* aActor)
+      : mActor(aActor)
+    {
+      MOZ_ASSERT(mActor);
+      mActor->Lock();
+    }
+
+    ~AutoLock()
+    {
+      mActor->Unlock();
+    }
+  };
+
   CacheChild();
   ~CacheChild();
 
   void SetListener(Cache* aListener);
 
   // Must be called by the associated Cache listener in its DestroyInternal()
   // method.  Also, Cache must call StartDestroyFromListener() on the actor in
   // its destructor to trigger ActorDestroy() if it has not been called yet.
@@ -69,22 +87,34 @@ private:
 
   virtual bool
   DeallocPCachePushStreamChild(PCachePushStreamChild* aActor) override;
 
   // utility methods
   void
   NoteDeletedActor();
 
+  void
+  MaybeFlushDelayedDestroy();
+
+  // Methods used to temporarily force the actor alive.  Only called from
+  // AutoLock.
+  void
+  Lock();
+
+  void
+  Unlock();
+
   // Use a weak ref so actor does not hold DOM object alive past content use.
   // The Cache object must call ClearListener() to null this before its
   // destroyed.
   Cache* MOZ_NON_OWNING_REF mListener;
   uint32_t mNumChildActors;
   bool mDelayedDestroy;
+  bool mLocked;
 
   NS_DECL_OWNINGTHREAD
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla