Bug 1268559 - Add a safety shutdown timer in ContentChild. r=billm, a=sylvestre
authorJim Mathies <jmathies@mozilla.com>
Thu, 02 Jun 2016 07:52:17 -0500
changeset 333288 886d96d457218b4cabadb58dca020e888a753036
parent 333287 c629b5f1d41e2b9736cee9008585c31ecbda5b41
child 333289 c2507c070a5590e16b53cb75d211f06b44acfc54
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)
reviewersbillm, sylvestre
bugs1268559
milestone48.0a2
Bug 1268559 - Add a safety shutdown timer in ContentChild. r=billm, a=sylvestre MozReview-Commit-ID: FVnOvJzErpI
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2229,16 +2229,21 @@ ContentChild::RecvSetConnectivity(const 
   ioInternal->SetConnectivity(connectivity);
 
   return true;
 }
 
 void
 ContentChild::ActorDestroy(ActorDestroyReason why)
 {
+  if (mForceKillTimer) {
+    mForceKillTimer->Cancel();
+    mForceKillTimer = nullptr;
+  }
+
   if (AbnormalShutdown == why) {
     NS_WARNING("shutting down early because of crash!");
     ProcessChild::QuickExit();
   }
 
 #ifndef NS_FREE_PERMANENT_DATA
   // In release builds, there's no point in the content process
   // going through the full XPCOM shutdown path, because it doesn't
@@ -3006,16 +3011,40 @@ ContentChild::RecvDomainSetChanged(const
     default:
       NS_NOTREACHED("Unexpected changeType");
       return false;
   }
 
   return true;
 }
 
+void
+ContentChild::StartForceKillTimer()
+{
+  if (mForceKillTimer) {
+    return;
+  }
+
+  int32_t timeoutSecs = Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
+  if (timeoutSecs > 0) {
+    mForceKillTimer = do_CreateInstance("@mozilla.org/timer;1");
+    MOZ_ASSERT(mForceKillTimer);
+    mForceKillTimer->InitWithFuncCallback(ContentChild::ForceKillTimerCallback,
+      this,
+      timeoutSecs * 1000,
+      nsITimer::TYPE_ONE_SHOT);
+  }
+}
+
+/* static */ void
+ContentChild::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure)
+{
+  ProcessChild::QuickExit();
+}
+
 bool
 ContentChild::RecvShutdown()
 {
   if (mPolicy) {
     mPolicy->Deactivate();
     mPolicy = nullptr;
   }
 
@@ -3035,16 +3064,21 @@ ContentChild::RecvShutdown()
   if (profiler_is_active()) {
     // We're shutting down while we were profiling. Send the
     // profile up to the parent so that we don't lose this
     // information.
     Unused << RecvGatherProfile();
   }
 #endif
 
+  // Start a timer that will insure we quickly exit after a reasonable
+  // period of time. Prevents shutdown hangs after our connection to the
+  // parent closes.
+  StartForceKillTimer();
+
   // Ignore errors here. If this fails, the parent will kill us after a
   // timeout.
   Unused << SendFinishShutdown();
   return true;
 }
 
 PBrowserOrId
 ContentChild::GetBrowserOrId(TabChild* aTabChild)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -607,16 +607,19 @@ public:
 
   // Windows specific - set up audio session
   virtual bool
   RecvSetAudioSessionData(const nsID& aId,
                           const nsString& aDisplayName,
                           const nsString& aIconPath) override;
 
 private:
+  static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
+  void StartForceKillTimer();
+
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   virtual void ProcessingError(Result aCode, const char* aReason) override;
 
   InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
   RefPtr<ConsoleListener> mConsoleListener;
 
   nsTHashtable<nsPtrHashKey<nsIObserver>> mIdleObservers;
@@ -638,16 +641,17 @@ private:
   bool mIsForBrowser;
   bool mCanOverrideProcessName;
   bool mIsAlive;
   nsString mProcessName;
 
   static ContentChild* sSingleton;
 
   nsCOMPtr<nsIDomainPolicy> mPolicy;
+  nsCOMPtr<nsITimer> mForceKillTimer;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 void
 InitOnContentProcessCreated();
 
 uint64_t