Remove racy ImageBridgeChild shutdown/creation checks. (bug 1298938 part 4, r=nical)
authorDavid Anderson <danderson@mozilla.com>
Tue, 13 Sep 2016 16:30:57 -0700
changeset 339493 84560a23836b1f4ef01c9f7c63f47ccce1abc285
parent 339492 92de67e547206478ca7daef0f7a3c38313ed98a3
child 339494 2d2b7d0a949aa6d6322fa93c01d9bb185b89cc8e
push id10033
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:50:26 +0000
treeherdermozilla-aurora@5dddbefdf759 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1298938
milestone51.0a1
Remove racy ImageBridgeChild shutdown/creation checks. (bug 1298938 part 4, r=nical)
dom/canvas/OffscreenCanvas.cpp
dom/media/systemservices/MediaSystemResourceManager.cpp
gfx/ipc/GPUProcessManager.cpp
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
--- a/dom/canvas/OffscreenCanvas.cpp
+++ b/dom/canvas/OffscreenCanvas.cpp
@@ -142,20 +142,19 @@ OffscreenCanvas::GetContext(JSContext* a
         contextType == CanvasContextType::WebGL2) {
       WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
       gl::GLContext* gl = webGL->GL();
       mCanvasRenderer->mContext = mCurrentContext;
       mCanvasRenderer->SetActiveThread();
       mCanvasRenderer->mGLContext = gl;
       mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha);
 
-      if (ImageBridgeChild::IsCreated()) {
+      if (RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton()) {
         TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
-        mCanvasClient = ImageBridgeChild::GetSingleton()->
-          CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags);
+        mCanvasClient = imageBridge->CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags);
         mCanvasRenderer->SetCanvasClient(mCanvasClient);
 
         gl::GLScreenBuffer* screen = gl->Screen();
         gl::SurfaceCaps caps = screen->mCaps;
         auto forwarder = mCanvasClient->GetForwarder();
 
         UniquePtr<gl::SurfaceFactory> factory =
           gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
--- a/dom/media/systemservices/MediaSystemResourceManager.cpp
+++ b/dom/media/systemservices/MediaSystemResourceManager.cpp
@@ -37,17 +37,18 @@ MediaSystemResourceManager::Shutdown()
     sSingleton->CloseIPC();
     sSingleton = nullptr;
   }
 }
 
 /* static */ void
 MediaSystemResourceManager::Init()
 {
-  if (!ImageBridgeChild::IsCreated()) {
+  RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
+  if (!imageBridge) {
     NS_WARNING("ImageBridge does not exist");
     return;
   }
 
   if (InImageBridgeChildThread()) {
     if (!sSingleton) {
 #ifdef DEBUG
       static int timesCreated = 0;
@@ -68,17 +69,17 @@ MediaSystemResourceManager::Init()
       if (!sSingleton) {
         sSingleton = new MediaSystemResourceManager();
       }
       ReentrantMonitorAutoEnter childThreadAutoMon(barrier);
       done = true;
       barrier.NotifyAll();
     });
 
-  ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(runnable.forget());
+  imageBridge->GetMessageLoop()->PostTask(runnable.forget());
 
   // should stop the thread until done.
   while (!done) {
     barrier.Wait();
   }
 }
 
 MediaSystemResourceManager::MediaSystemResourceManager()
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -146,17 +146,17 @@ GPUProcessManager::EnsureGPUReady()
   if (mGPUChild) {
     mGPUChild->EnsureGPUReady();
   }
 }
 
 void
 GPUProcessManager::EnsureImageBridgeChild()
 {
-  if (ImageBridgeChild::IsCreated()) {
+  if (ImageBridgeChild::GetSingleton()) {
     return;
   }
 
   EnsureGPUReady();
 
   if (!mGPUChild) {
     ImageBridgeChild::InitSameProcess();
     return;
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -163,19 +163,16 @@ struct CompositableTransaction
 };
 
 struct AutoEndTransaction {
   explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
   ~AutoEndTransaction() { mTxn->End(); }
   CompositableTransaction* mTxn;
 };
 
-/* static */
-Atomic<bool> ImageBridgeChild::sIsShutDown(false);
-
 void
 ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
                               const nsTArray<TimedTextureClient>& aTextures)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aCompositable->GetIPDLActor());
   MOZ_ASSERT(aCompositable->IsConnected());
 
@@ -492,17 +489,27 @@ ImageBridgeChild::ShutdownStep1(Synchron
 void
 ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
 {
   AutoCompleteTask complete(aTask);
 
   MOZ_ASSERT(InImageBridgeChildThread(),
              "Should be in ImageBridgeChild thread.");
 
-  Close();
+  if (!mCalledClose) {
+    Close();
+    mCalledClose = true;
+  }
+}
+
+void
+ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mCanSend = false;
+  mCalledClose = true;
 }
 
 void
 ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
                                         RefPtr<ImageClient>* result,
                                         CompositableType aType,
                                         ImageContainer* aImageContainer,
                                         ImageContainerChild* aContainerChild)
@@ -518,17 +525,18 @@ ImageBridgeChild::CreateCanvasClientSync
                                          TextureFlags aFlags,
                                          RefPtr<CanvasClient>* const outResult)
 {
   AutoCompleteTask complete(aTask);
   *outResult = CreateCanvasClientNow(aType, aFlags);
 }
 
 ImageBridgeChild::ImageBridgeChild()
-  : mShuttingDown(false)
+  : mCanSend(false)
+  , mCalledClose(false)
   , mFwdTransactionId(0)
 #ifdef MOZ_WIDGET_GONK
   , mWaitingFenceHandleMutex("ImageBridgeChild::mWaitingFenceHandleMutex")
 #endif
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mTxn = new CompositableTransaction();
@@ -542,30 +550,29 @@ ImageBridgeChild::~ImageBridgeChild()
   MOZ_ASSERT(!mShutdownObserver);
 
   delete mTxn;
 }
 
 void
 ImageBridgeChild::MarkShutDown()
 {
-  MOZ_ASSERT(!mShuttingDown);
   mTexturesWaitingRecycled.Clear();
   mTrackersHolder.DestroyAsyncTransactionTrackersHolder();
 
-  mShuttingDown = true;
+  mCanSend = false;
 }
 
 void
 ImageBridgeChild::Connect(CompositableClient* aCompositable,
                           ImageContainer* aImageContainer)
 {
   MOZ_ASSERT(aCompositable);
-  MOZ_ASSERT(!mShuttingDown);
   MOZ_ASSERT(InImageBridgeChildThread());
+  MOZ_ASSERT(CanSend());
 
   uint64_t id = 0;
 
   PImageContainerChild* imageContainerChild = nullptr;
   if (aImageContainer)
     imageContainerChild = aImageContainer->GetPImageContainerChild();
 
   PCompositableChild* child =
@@ -574,17 +581,17 @@ ImageBridgeChild::Connect(CompositableCl
   MOZ_ASSERT(child);
   aCompositable->InitIPDLActor(child, id);
 }
 
 PCompositableChild*
 ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo,
                                           PImageContainerChild* aChild, uint64_t* aID)
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   return AsyncCompositableChild::CreateActor();
 }
 
 bool
 ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
 {
   AsyncCompositableChild::DestroyActor(aActor);
   return true;
@@ -596,21 +603,16 @@ Thread* ImageBridgeChild::GetThread() co
   return sImageBridgeChildThread;
 }
 
 ImageBridgeChild* ImageBridgeChild::GetSingleton()
 {
   return sImageBridgeChildSingleton;
 }
 
-bool ImageBridgeChild::IsCreated()
-{
-  return GetSingleton() != nullptr;
-}
-
 void
 ImageBridgeChild::ReleaseImageContainer(RefPtr<ImageContainerChild> aChild)
 {
   if (!aChild) {
     return;
   }
 
   if (!InImageBridgeChildThread()) {
@@ -656,35 +658,34 @@ ImageBridgeChild::DispatchReleaseTexture
     &ImageBridgeChild::ReleaseTextureClientNow,
     aClient);
   imageBridge->GetMessageLoop()->PostTask(runnable.forget());
 }
 
 void
 ImageBridgeChild::UpdateImageClient(RefPtr<ImageClient> aClient, RefPtr<ImageContainer> aContainer)
 {
-  if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) {
-    NS_WARNING("Something is holding on to graphics resources after the shutdown"
-               "of the graphics subsystem!");
-    return;
-  }
-  if (!aClient || !aContainer || !IsCreated()) {
+  if (!aClient || !aContainer) {
     return;
   }
 
   if (!InImageBridgeChildThread()) {
     RefPtr<Runnable> runnable = WrapRunnable(
       RefPtr<ImageBridgeChild>(this),
       &ImageBridgeChild::UpdateImageClient,
       aClient,
       aContainer);
     GetMessageLoop()->PostTask(runnable.forget());
     return;
   }
 
+  if (!CanSend()) {
+    return;
+  }
+
   // If the client has become disconnected before this event was dispatched,
   // early return now.
   if (!aClient->IsConnected()) {
     return;
   }
 
   BeginTransaction();
   aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
@@ -720,16 +721,21 @@ ImageBridgeChild::UpdateAsyncCanvasRende
 
   task.Wait();
 }
 
 void
 ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
 {
   MOZ_ASSERT(aWrapper);
+
+  if (!CanSend()) {
+    return;
+  }
+
   BeginTransaction();
   aWrapper->GetCanvasClient()->Updated();
   EndTransaction();
 }
 
 void
 ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
                                      ImageClient* aClient,
@@ -739,24 +745,17 @@ ImageBridgeChild::FlushAllImagesSync(Syn
 #ifdef MOZ_WIDGET_GONK
   MOZ_ASSERT(aWaiter);
 #else
   MOZ_ASSERT(!aWaiter);
 #endif
 
   AutoCompleteTask complete(aTask);
 
-  if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) {
-    // How sad. If we get into this branch it means that the ImageBridge
-    // got destroyed between the time we ImageBridgeChild::FlushAllImage
-    // was called on some thread, and the time this function was proxied
-    // to the ImageBridge thread. ImageBridge gets destroyed way to late
-    // in the shutdown of gecko for this to be happening for a good reason.
-    NS_WARNING("Something is holding on to graphics resources after the shutdown"
-               "of the graphics subsystem!");
+  if (!CanSend()) {
 #ifdef MOZ_WIDGET_GONK
     aWaiter->DecrementWaitCount();
 #endif
     return;
   }
 
   MOZ_ASSERT(aClient);
   BeginTransaction();
@@ -772,22 +771,19 @@ ImageBridgeChild::FlushAllImagesSync(Syn
 #ifdef MOZ_WIDGET_GONK
   aWaiter->DecrementWaitCount();
 #endif
 }
 
 void
 ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer)
 {
-  if (!IsCreated() || IsShutDown()) {
-    return;
-  }
   MOZ_ASSERT(aClient);
-  MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown);
   MOZ_ASSERT(!InImageBridgeChildThread());
+
   if (InImageBridgeChildThread()) {
     NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
     return;
   }
 
   SynchronousTask task("FlushAllImages Lock");
 
   RefPtr<AsyncTransactionWaiter> waiter;
@@ -812,26 +808,26 @@ ImageBridgeChild::FlushAllImages(ImageCl
 #ifdef MOZ_WIDGET_GONK
   waiter->WaitComplete();
 #endif
 }
 
 void
 ImageBridgeChild::BeginTransaction()
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
   UpdateFwdTransactionId();
   mTxn->Begin();
 }
 
 void
 ImageBridgeChild::EndTransaction()
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
 
   AutoEndTransaction _(mTxn);
 
   if (mTxn->IsEmpty()) {
     return;
   }
 
@@ -902,50 +898,50 @@ ImageBridgeChild::InitForContent(Endpoin
 
 void
 ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint)
 {
   if (!aEndpoint.Bind(this)) {
     return;
   }
 
+  mCanSend = true;
+
   SendImageBridgeThreadId();
 }
 
 void
 ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent)
 {
   MessageLoop *parentMsgLoop = aParent->GetMessageLoop();
   ipc::MessageChannel *parentChannel = aParent->GetIPCChannel();
   Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
 
+  mCanSend = true;
+
   SendImageBridgeThreadId();
 }
 
 void ImageBridgeChild::ShutDown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  sIsShutDown = true;
-
   if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
     child->WillShutdown();
 
     sImageBridgeChildSingleton = nullptr;
   }
 
   delete sImageBridgeChildThread;
   sImageBridgeChildThread = nullptr;
 }
 
 void
 ImageBridgeChild::WillShutdown()
 {
-  MOZ_ASSERT(!mShuttingDown);
-
   {
     SynchronousTask task("ImageBridge ShutdownStep1 lock");
 
     RefPtr<Runnable> runnable = WrapRunnable(
       RefPtr<ImageBridgeChild>(this),
       &ImageBridgeChild::ShutdownStep1,
       &task);
     GetMessageLoop()->PostTask(runnable.forget());
@@ -1012,17 +1008,17 @@ ImageBridgeChild::InitWithGPUProcess(End
 
   MessageLoop* loop = sImageBridgeChildSingleton->GetMessageLoop();
   loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
     sImageBridgeChildSingleton, &ImageBridgeChild::Bind, Move(aEndpoint)));
 }
 
 bool InImageBridgeChildThread()
 {
-  return ImageBridgeChild::IsCreated() &&
+  return sImageBridgeChildThread &&
     sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
 }
 
 MessageLoop * ImageBridgeChild::GetMessageLoop() const
 {
   return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr;
 }
 
@@ -1062,17 +1058,16 @@ ImageBridgeChild::CreateImageClient(Comp
   return result;
 }
 
 RefPtr<ImageClient>
 ImageBridgeChild::CreateImageClientNow(CompositableType aType,
                                        ImageContainer* aImageContainer,
                                        ImageContainerChild* aContainerChild)
 {
-  MOZ_ASSERT(!mShuttingDown);
   MOZ_ASSERT(InImageBridgeChildThread());
 
   if (aImageContainer) {
     SendPImageContainerConstructor(aContainerChild);
     aContainerChild->RegisterWithIPDL();
   }
 
   RefPtr<ImageClient> client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
@@ -1122,36 +1117,35 @@ ImageBridgeChild::CreateCanvasClientNow(
   return client.forget();
 }
 
 bool
 ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
                                    ipc::SharedMemory::SharedMemoryType aType,
                                    ipc::Shmem* aShmem)
 {
-  MOZ_ASSERT(!mShuttingDown);
-  if (InImageBridgeChildThread()) {
-    return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
-  } else {
+  if (!InImageBridgeChildThread()) {
     return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe
   }
+
+  MOZ_ASSERT(CanSend());
+  return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
 }
 
 bool
 ImageBridgeChild::AllocShmem(size_t aSize,
                              ipc::SharedMemory::SharedMemoryType aType,
                              ipc::Shmem* aShmem)
 {
-  MOZ_ASSERT(!mShuttingDown);
-  if (InImageBridgeChildThread()) {
-    return PImageBridgeChild::AllocShmem(aSize, aType,
-                                         aShmem);
-  } else {
+  if (!InImageBridgeChildThread()) {
     return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
   }
+
+  MOZ_ASSERT(CanSend());
+  return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
 }
 
 // NewRunnableFunction accepts a limited number of parameters so we need a
 // struct here
 struct AllocShmemParams {
   RefPtr<ISurfaceAllocator> mAllocator;
   size_t mSize;
   ipc::SharedMemory::SharedMemoryType mType;
@@ -1237,30 +1231,30 @@ ImageBridgeChild::DeallocShmem(ipc::Shme
 }
 
 PTextureChild*
 ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
                                      const LayersBackend&,
                                      const TextureFlags&,
                                      const uint64_t& aSerial)
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   return TextureClient::CreateIPDLActor();
 }
 
 bool
 ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
 {
   return TextureClient::DestroyIPDLActor(actor);
 }
 
 PMediaSystemResourceManagerChild*
 ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   return new mozilla::media::MediaSystemResourceManagerChild();
 }
 
 bool
 ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
 {
   MOZ_ASSERT(aActor);
   delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
@@ -1350,17 +1344,17 @@ ImageBridgeChild::RecvDidComposite(Infal
 }
 
 PTextureChild*
 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 LayersBackend aLayersBackend,
                                 TextureFlags aFlags,
                                 uint64_t aSerial)
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
 }
 
 static bool
 IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op, bool synchronously)
 {
   if (aTxn->Finished()) {
     return false;
@@ -1387,17 +1381,17 @@ ImageBridgeChild::DestroyInTransaction(P
   return IBCAddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
 }
 
 
 void
 ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                 TextureClient* aTexture)
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->IsSharedWithCompositor());
   MOZ_ASSERT(aCompositable->IsConnected());
   if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
     return;
   }
 
   CompositableOperation op(
@@ -1411,17 +1405,17 @@ ImageBridgeChild::RemoveTextureFromCompo
   }
 }
 
 void
 ImageBridgeChild::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                      CompositableClient* aCompositable,
                                                      TextureClient* aTexture)
 {
-  MOZ_ASSERT(!mShuttingDown);
+  MOZ_ASSERT(CanSend());
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->IsSharedWithCompositor());
   MOZ_ASSERT(aCompositable->IsConnected());
   if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
     return;
   }
 
   CompositableOperation op(
@@ -1451,16 +1445,23 @@ ImageBridgeChild::Destroy(CompositableCh
       &ImageBridgeChild::Destroy,
       RefPtr<CompositableChild>(aCompositable));
     GetMessageLoop()->PostTask(runnable.forget());
     return;
   }
   CompositableForwarder::Destroy(aCompositable);
 }
 
+bool
+ImageBridgeChild::CanSend() const
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+  return mCanSend;
+}
+
 void
 ImageBridgeChild::OnXPCOMShutdown()
 {
   // This uses nsIObserverService, so it must be cleaned up. Other threads may
   // hold references to ImageBridgeChild and we may actually be destroyed well
   // after XPCOM shutdown.
   mActiveResourceTracker = nullptr;
 }
@@ -1486,11 +1487,10 @@ ImageBridgeChild::ShutdownObserver::Obse
                                             const char16_t* aData)
 {
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     mImageBridge->OnXPCOMShutdown();
   }
   return NS_OK;
 }
 
-
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -134,32 +134,16 @@ public:
    * ImageBridge's thread.
    *
    * If you don't want to destroy the thread, call DestroyBridge directly
    * instead.
    */
   static void ShutDown();
 
   /**
-   * Returns true if the singleton has been created.
-   *
-   * Can be called from any thread.
-   */
-  static bool IsCreated();
-  /**
-   * Returns true if the singleton's ShutDown() was called.
-   *
-   * Can be called from any thread.
-   */
-  static bool IsShutDown()
-  {
-    return sIsShutDown;
-  }
-
-  /**
    * returns the singleton instance.
    *
    * can be called from any thread.
    */
   static ImageBridgeChild* GetSingleton();
 
 
   static void IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier);
@@ -396,16 +380,20 @@ protected:
   void SendImageBridgeThreadId();
 
   void WillShutdown();
   void ShutdownStep1(SynchronousTask* aTask);
   void ShutdownStep2(SynchronousTask* aTask);
   void MarkShutDown();
   void FallbackDestroyActors();
 
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  bool CanSend() const;
+
 private:
   class ShutdownObserver final : public nsIObserver
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
 
     explicit ShutdownObserver(ImageBridgeChild* aImageBridge);
@@ -417,18 +405,19 @@ private:
     ImageBridgeChild* mImageBridge;
   };
   friend class ShutdownObserver;
 
   void OnXPCOMShutdown();
 
 private:
   CompositableTransaction* mTxn;
-  Atomic<bool> mShuttingDown;
-  static Atomic<bool> sIsShutDown;
+
+  bool mCanSend;
+  bool mCalledClose;
 
   /**
    * Transaction id of CompositableForwarder.
    * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call.
    */
   uint64_t mFwdTransactionId;
 
   /**