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 313834 84560a23836b1f4ef01c9f7c63f47ccce1abc285
parent 313833 92de67e547206478ca7daef0f7a3c38313ed98a3
child 313835 2d2b7d0a949aa6d6322fa93c01d9bb185b89cc8e
push id32264
push usercbook@mozilla.com
push dateWed, 14 Sep 2016 10:18:20 +0000
treeherderautoland@b9c4a0402a0a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1298938
milestone51.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
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;
 
   /**