Bug 1037625 - Allow child processes to respond to 'inner-window-destroyed' notifications without possibly killing the process. r-khuey.
authorBen Turner <bent.mozilla@gmail.com>
Fri, 11 Jul 2014 11:15:10 -0700
changeset 241259 2cae53b8f3f43f3a2f4feba43ed4856fc71a8437
parent 241258 1fe4af5711ac8d338b2397c2ccfad831d65c2067
child 241260 6ac6c1eabd76dc3c08a710f5ad854d9e93a5def8
push idunknown
push userunknown
push dateunknown
bugs1037625
milestone36.0a1
Bug 1037625 - Allow child processes to respond to 'inner-window-destroyed' notifications without possibly killing the process. r-khuey.
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -745,16 +745,49 @@ private:
         MOZ_ASSERT(NS_IsMainThread());
         MOZ_ASSERT(mInfo);
 
         mInfo->FireCallback();
         return NS_OK;
     }
 };
 
+class TabChild::DelayedDeleteRunnable MOZ_FINAL
+  : public nsRunnable
+{
+    nsRefPtr<TabChild> mTabChild;
+
+public:
+    DelayedDeleteRunnable(TabChild* aTabChild)
+      : mTabChild(aTabChild)
+    {
+        MOZ_ASSERT(NS_IsMainThread());
+        MOZ_ASSERT(aTabChild);
+    }
+
+private:
+    ~DelayedDeleteRunnable()
+    {
+        MOZ_ASSERT(NS_IsMainThread());
+        MOZ_ASSERT(!mTabChild);
+    }
+
+    NS_IMETHOD
+    Run()
+    {
+        MOZ_ASSERT(NS_IsMainThread());
+        MOZ_ASSERT(mTabChild);
+
+        unused << PBrowserChild::Send__delete__(mTabChild);
+
+        mTabChild = nullptr;
+        return NS_OK;
+    }
+};
+
 StaticRefPtr<TabChild> sPreallocatedTab;
 
 /*static*/
 std::map<TabId, nsRefPtr<TabChild>>&
 TabChild::NestedTabChildMap()
 {
   MOZ_ASSERT(NS_IsMainThread());
   static std::map<TabId, nsRefPtr<TabChild>> sNestedTabChildMap;
@@ -2743,17 +2776,22 @@ TabChild::RecvDestroy()
     mozilla::services::GetObserverService();
 
   observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
   observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
 
   // XXX what other code in ~TabChild() should we be running here?
   DestroyWindow();
 
-  return Send__delete__(this);
+  // Bounce through the event loop once to allow any delayed teardown runnables
+  // that were just generated to have a chance to run.
+  nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this);
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(deleteRunnable)));
+
+  return true;
 }
 
 bool
 TabChild::RecvSetUpdateHitRegion(const bool& aEnabled)
 {
     mUpdateHitRegion = aEnabled;
     return true;
 }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -578,16 +578,17 @@ private:
       MOZ_ASSERT(mUniqueId == 0);
 
       mUniqueId = aTabId;
       NestedTabChildMap()[mUniqueId] = this;
     }
 
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
+    class DelayedDeleteRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
     RenderFrameChild* mRemoteFrame;
     nsRefPtr<nsIContentChild> mManager;
     uint32_t mChromeFlags;