Bug 1261347 - Make some noise when things are deallocated late during shutdown. r=edwin
☠☠ backed out by 0a1722feaf7b ☠ ☠
authorNicolas Silva <nsilva@mozilla.com>
Wed, 13 Apr 2016 15:50:08 +0200
changeset 330902 4b36ba6198154815e958ebeb1e08ce631e36bbb6
parent 330901 685e89b31d6b9814d95c3678b7bf8ecafee245a0
child 330903 beb7e5d6538b4ccf13db9d282075f99eaf23b2ca
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1261347
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1261347 - Make some noise when things are deallocated late during shutdown. r=edwin
gfx/layers/ImageContainer.cpp
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/LayerTransactionChild.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -196,16 +196,25 @@ ImageContainer::ImageContainer(Mode flag
         break;
     }
   }
 }
 
 ImageContainer::~ImageContainer()
 {
   if (IsAsync()) {
+
+    if (gfxPlatform::IPCAlreadyShutDown()) {
+      printf_stderr("!![ImageBridge] an ImageContainer is Destroyed late "
+                    "during shutdown!!\n");
+#ifdef GFX_STRICT_SHUTDOWN
+      MOZ_CRASH("This ImageContainer is deleted too late.");
+#endif
+    }
+
     mIPDLChild->ForgetImageContainer();
     ImageBridgeChild::DispatchReleaseImageClient(mImageClient, mIPDLChild);
   }
 }
 
 RefPtr<PlanarYCbCrImage>
 ImageContainer::CreatePlanarYCbCrImage()
 {
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -140,16 +140,23 @@ CompositableClient::CompositableClient(C
 , mTextureFlags(aTextureFlags)
 {
   MOZ_COUNT_CTOR(CompositableClient);
 }
 
 CompositableClient::~CompositableClient()
 {
   MOZ_COUNT_DTOR(CompositableClient);
+
+#ifdef GFX_STRICT_SHUTDOWN
+  if (gfxPlatform::IPCAlreadyShutDown()) {
+    MOZ_CRASH("This CompositableClient is deleted too late.");
+  }
+#endif
+
   Destroy();
 }
 
 LayersBackend
 CompositableClient::GetCompositorBackendType() const
 {
   return mForwarder->GetCompositorBackendType();
 }
@@ -180,31 +187,33 @@ CompositableClient::Connect(ImageContain
 bool
 CompositableClient::IsConnected() const
 {
   return mCompositableChild && mCompositableChild->CanSend();
 }
 
 // static
 void
-CompositableClient::ForceIPDLActorShutdown(PCompositableChild* aActor)
+CompositableClient::ForceIPDLActorShutdown(PCompositableChild* aActor,
+                                           const char* const aProtocolName)
 {
   if (!aActor) {
     return;
   }
 
   auto actor = CompositableChild::Cast(aActor);
   if (actor->CanSend()) {
 #ifdef DEBUG
     // Making it an assertion would blow up too often during test runs so
     // let's keep it a simple printf for now. This is happening during shutdown
     // so we don't have to worry too much about printf being slow.
     // More involved reporting like crashstats annotations would be too much noise
     // at this point.
-    printf("!! A CompositableClient is destroyed late during shutdown !!\n");
+    printf_stderr("!![%s] A CompositableClient is destroyed late during shutdown!!\n",
+                  aProtocolName);
 #endif
 
     // Do not access the CompositableClient from here.
     // Do not call Destroy() either because that's how we know whether the
     // CompositableClient's destructor has run.
     actor->ForceActorShutdown();
   }
 }
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -225,17 +225,18 @@ public:
   static bool DeallocIPDLActor(PCompositableChild* actor);
 
   /// Ideally we would not need this. When we shut top-level IPDL protocols down,
   /// the remaining managed protocols need to be destroyed synchronously. We'd
   /// It'd be better if all ImageClients were alread destroyed by that time.
   /// Call this during shutdown instead of trying to access the CompositableClient
   /// since the latter may be about to get destroyed and we don't know for sure
   /// on which thread.
-  static void ForceIPDLActorShutdown(PCompositableChild* aActor);
+  static void ForceIPDLActorShutdown(PCompositableChild* aActor,
+                                     const char* const aProtocolName);
 
   void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
 
   static void TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId);
 
   static void HoldUntilComplete(PCompositableChild* aActor, AsyncTransactionTracker* aTracker);
 
   static uint64_t GetTrackersHolderId(PCompositableChild* aActor);
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -239,31 +239,33 @@ void DestroyTextureActorAndSharedData(Te
 
   } else {
     // aActor may get deleted in ReleaseActor.
     aActor->ReleaseActor(forwarder);
     // DestroyTextureData will be called by TextureChild::ActorDestroy
   }
 }
 
-void TextureClient::ForceIPDLActorShutdown(PTextureChild* aActor)
+void TextureClient::ForceIPDLActorShutdown(PTextureChild* aActor,
+                                           const char* const aProtocolName)
 {
   if (!aActor) {
     return;
   }
   auto actor = static_cast<TextureChild*>(aActor);
 
 #ifdef DEBUG
   // Making it an assertion would blow up too often during test runs so
   // let's keep it a simple printf for now. This is happening during shutdown
   // so we don't have to worry too much about printf being slow.
   // More involved reporting like crashstats annotations would be too much noise
   // at this point.
   if (actor->CanSend()) {
-    printf("!! A TextureClient is destroyed late during shutdown !!\n");
+    printf_stderr("!![%s] A TextureClient is destroyed late during shutdown!!\n",
+                  aProtocolName);
   }
 #endif
 
   DestroyTextureActorAndSharedData(actor);
 }
 
 /// The logic for synchronizing a TextureClient's deallocation goes here.
 ///
@@ -280,16 +282,17 @@ DeallocateTextureClient(TextureDeallocPa
   TextureChild* actor = params.actor;
   MessageLoop* ipdlMsgLoop = nullptr;
 
   if (params.allocator) {
     ipdlMsgLoop = params.allocator->AsClientAllocator()->GetMessageLoop();
     if (!ipdlMsgLoop) {
       // An allocator with no message loop means we are too late in the shutdown
       // sequence.
+      printf_stderr("!!A TextureClient destroyed after its IPDL thread !!\n");
       return;
     }
   }
 
   // First make sure that the work is happening on the IPDL thread.
   if (ipdlMsgLoop && MessageLoop::current() != ipdlMsgLoop) {
     if (params.syncDeallocation) {
       bool done = false;
@@ -466,16 +469,22 @@ gfx::SurfaceFormat
 TextureClient::GetFormat() const
 {
   MOZ_ASSERT(IsValid());
   return mData->GetFormat();
 }
 
 TextureClient::~TextureClient()
 {
+#ifdef GFX_STRICT_SHUTDOWN
+  if (gfxPlatform::IPCAlreadyShutDown()) {
+    MOZ_CRASH("This TextureClient is deleted too late.");
+  }
+#endif
+
   Destroy(false);
 }
 
 void
 TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(mIsLocked);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -424,17 +424,18 @@ public:
    *
    * TextureChild is an implementation detail of TextureClient that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPextureChild and DeallocPTextureChild).
    */
   static PTextureChild* CreateIPDLActor();
   static bool DeallocIPDLActor(PTextureChild* actor);
-  static void ForceIPDLActorShutdown(PTextureChild* actor);
+  static void ForceIPDLActorShutdown(PTextureChild* actor,
+                                     const char* const aProtocolName);
   // call this if the transaction that was supposed to destroy the actor failed.
   static bool DestroyFallback(PTextureChild* actor);
 
   /**
    * Get the TextureClient corresponding to the actor passed in parameter.
    */
   static TextureClient* AsTextureClient(PTextureChild* actor);
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -262,22 +262,22 @@ static void ImageBridgeShutdownStep1(Ree
 
   MediaSystemResourceManager::Shutdown();
 
   if (sImageBridgeChildSingleton) {
     // Force all managed protocols to shut themselves down cleanly
     InfallibleTArray<PCompositableChild*> compositables;
     sImageBridgeChildSingleton->ManagedPCompositableChild(compositables);
     for (int i = compositables.Length() - 1; i >= 0; --i) {
-      CompositableClient::ForceIPDLActorShutdown(compositables[i]);
+      CompositableClient::ForceIPDLActorShutdown(compositables[i], "ImageBridge");
     }
     InfallibleTArray<PTextureChild*> textures;
     sImageBridgeChildSingleton->ManagedPTextureChild(textures);
     for (int i = textures.Length() - 1; i >= 0; --i) {
-      TextureClient::ForceIPDLActorShutdown(textures[i]);
+      TextureClient::ForceIPDLActorShutdown(textures[i], "ImageBridge");
     }
     sImageBridgeChildSingleton->FallbackDestroyActors();
 
     sImageBridgeChildSingleton->SendWillClose();
     sImageBridgeChildSingleton->MarkShutDown();
     // From now on, no message can be sent through the image bridge from the
     // client side except the final Stop message.
   }
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -34,22 +34,22 @@ LayerTransactionChild::Destroy()
   // When it happens, IPCOpen() is still true.
   // See bug 1004191.
   mDestroyed = true;
   MOZ_ASSERT(0 == ManagedPLayerChild().Count(),
              "layers should have been cleaned up by now");
 
   const ManagedContainer<PCompositableChild>& compositables = ManagedPCompositableChild();
   for (auto iter = compositables.ConstIter(); !iter.Done(); iter.Next()) {
-    CompositableClient::ForceIPDLActorShutdown(iter.Get()->GetKey());
+    CompositableClient::ForceIPDLActorShutdown(iter.Get()->GetKey(), "CompositorBridge");
   }
 
   const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
   for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
-    TextureClient::ForceIPDLActorShutdown(iter.Get()->GetKey());
+    TextureClient::ForceIPDLActorShutdown(iter.Get()->GetKey(), "CompositorBridge");
   }
 
   SendShutdown();
 }
 
 
 PLayerChild*
 LayerTransactionChild::AllocPLayerChild()
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -859,25 +859,25 @@ gfxPlatform::InitLayersIPC()
     {
         mozilla::layers::CompositorBridgeParent::StartUp();
 #ifdef MOZ_WIDGET_GONK
         SharedBufferManagerChild::StartUp();
 #endif
         mozilla::layers::ImageBridgeChild::StartUp();
         gfx::VRManagerChild::StartUpSameProcess();
     }
+
 }
 
 /* static */ void
 gfxPlatform::ShutdownLayersIPC()
 {
     if (!sLayersIPCIsUp) {
       return;
     }
-    sLayersIPCIsUp = false;
 
     if (XRE_IsContentProcess()) {
 
         gfx::VRManagerChild::ShutDown();
         // cf bug 1215265.
         if (gfxPrefs::ChildProcessShutdown()) {
           layers::ImageBridgeChild::ShutDown();
           layers::CompositorBridgeChild::ShutDown();
@@ -894,16 +894,24 @@ gfxPlatform::ShutdownLayersIPC()
 #endif
 
         // This has to happen after shutting down the child protocols.
         layers::CompositorBridgeParent::ShutDown();
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
+
+    sLayersIPCIsUp = false;
+}
+
+// static
+bool gfxPlatform::IPCAlreadyShutDown()
+{
+  return !sLayersIPCIsUp;
 }
 
 gfxPlatform::~gfxPlatform()
 {
     mScreenReferenceSurface = nullptr;
     mScreenReferenceDrawTarget = nullptr;
 
     // The cairo folks think we should only clean up in debug builds,
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -168,16 +168,17 @@ public:
     /**
      * Shut down Thebes.
      * Init() arranges for this to be called at an appropriate time.
      */
     static void Shutdown();
 
     static void InitLayersIPC();
     static void ShutdownLayersIPC();
+    static bool IPCAlreadyShutDown();
 
     /**
      * Create an offscreen surface of the given dimensions
      * and image format.
      */
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& aSize,
                              gfxImageFormat aFormat) = 0;