Bug 1037725 - Add warning message in the console when worker spawn over limit. r=khuey
authorJohn Dai <jdai@mozilla.com>
Tue, 12 Apr 2016 01:41:00 +0200
changeset 331134 ca9577b9e37a277d970e65ccbee3189d559e7484
parent 331133 f81406821d565c0d9d5d5d9120f0b4b4347a3c5b
child 331135 a9cfac4ce926828806b6fa4247c10d113866b9ac
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)
reviewerskhuey
bugs1037725
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 1037725 - Add warning message in the console when worker spawn over limit. r=khuey
dom/locales/en-US/chrome/dom/dom.properties
dom/workers/RuntimeService.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -158,18 +158,18 @@ DataContainerEventWarning=Use of DataCon
 # LOCALIZATION NOTE: Do not translate "window.controllers"
 Window_ControllersWarning=window.controllers is deprecated. Do not use it for UA detection.
 ImportXULIntoContentWarning=Importing XUL nodes into a content document is deprecated. This functionality may be removed soon.
 XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead.
 # LOCALIZATION NOTE: Do not translate "IndexedDB".
 IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation.
 # LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S are numbers.
 IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. Budget limit is the document surface area multiplied by %1$S (%2$S px). Occurrences of will-change over the budget will be ignored.
-# LOCALIZATION NOTE: Do not translate "ServiceWorker".
-HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed.
+# LOCALIZATION NOTE: Do not translate "Worker".
+HittingMaxWorkersPerDomain2=A Worker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The Worker is now queued and will be started after some of the other workers have completed.
 # LOCALIZATION NOTE: Do not translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor"
 PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener, and speedOfSound and dopplerFactor on the AudioListener are deprecated and those members will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/AudioListener#Deprecated_features
 # LOCALIZATION NOTE: Do not translate "Application Cache API", "AppCache" and "ServiceWorker".
 AppCacheWarning=The Application Cache API (AppCache) is deprecated and will be removed at a future date.  Please consider using ServiceWorker for offline support.
 # LOCALIZATION NOTE: Do not translate "Worker".
 EmptyWorkerSourceWarning=Attempting to create a Worker from an empty source. This is probably unintentional.
 WebrtcDeprecatedPrefixWarning=WebRTC interfaces with the "moz" prefix (mozRTCPeerConnection, mozRTCSessionDescription, mozRTCIceCandidate) have been deprecated.
 NavigatorGetUserMediaWarning=navigator.mozGetUserMedia has been replaced by navigator.mediaDevices.getUserMedia
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1456,27 +1456,22 @@ RuntimeService::RegisterWorker(WorkerPri
 
     queued = gMaxWorkersPerDomain &&
              domainInfo->ActiveWorkerCount() >= gMaxWorkersPerDomain &&
              !domain.IsEmpty() &&
              !exemptFromPerDomainMax;
 
     if (queued) {
       domainInfo->mQueuedWorkers.AppendElement(aWorkerPrivate);
+
+      // Worker spawn gets queued due to hitting max workers per domain
+      // limit so let's log a warning.
+      WorkerPrivate::ReportErrorToConsole("HittingMaxWorkersPerDomain2");
+
       if (isServiceWorker || isSharedWorker) {
-        AssertIsOnMainThread();
-        // ServiceWorker spawn gets queued due to hitting max workers per domain
-        // limit so let's log a warning.
-        // Note: aWorkerPrivate->GetDocument() call might result nullptr due to
-        // no window so the message warning will show up in the browser console.
-        nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
-                                        NS_LITERAL_CSTRING("DOM"),
-                                        aWorkerPrivate->GetDocument(),
-                                        nsContentUtils::eDOM_PROPERTIES,
-                                        "HittingMaxWorkersPerDomain");
         Telemetry::Accumulate(isSharedWorker ? Telemetry::SHARED_WORKER_SPAWN_GETS_QUEUED
                                              : Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1);
       }
     }
     else if (parent) {
       domainInfo->mChildWorkerCount++;
     }
     else if (isServiceWorker) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -934,16 +934,72 @@ public:
 private:
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     return aWorkerPrivate->ThawInternal();
   }
 };
 
+class ReportErrorToConsoleRunnable final : public WorkerRunnable
+{
+  const char* mMessage;
+
+public:
+  // aWorkerPrivate is the worker thread we're on (or the main thread, if null)
+  static void
+  Report(WorkerPrivate* aWorkerPrivate, const char* aMessage)
+  {
+    if (aWorkerPrivate) {
+      aWorkerPrivate->AssertIsOnWorkerThread();
+    } else {
+      AssertIsOnMainThread();
+    }
+
+    // Now fire a runnable to do the same on the parent's thread if we can.
+    if (aWorkerPrivate) {
+      RefPtr<ReportErrorToConsoleRunnable> runnable =
+        new ReportErrorToConsoleRunnable(aWorkerPrivate, aMessage);
+      runnable->Dispatch();
+      return;
+    }
+
+    // Log a warning to the console.
+    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                    NS_LITERAL_CSTRING("DOM"),
+                                    nullptr,
+                                    nsContentUtils::eDOM_PROPERTIES,
+                                    aMessage);
+  }
+
+private:
+  ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate, const char* aMessage)
+  : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
+    mMessage(aMessage)
+  { }
+
+  virtual void
+  PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
+  {
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    // Dispatch may fail if the worker was canceled, no need to report that as
+    // an error, so don't call base class PostDispatch.
+  }
+
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    WorkerPrivate* parent = aWorkerPrivate->GetParent();
+    MOZ_ASSERT_IF(!parent, NS_IsMainThread());
+    Report(parent, mMessage);
+    return true;
+  }
+};
+
 class ReportErrorRunnable final : public WorkerRunnable
 {
   nsString mMessage;
   nsString mFilename;
   nsString mLine;
   uint32_t mLineNumber;
   uint32_t mColumnNumber;
   uint32_t mFlags;
@@ -5844,16 +5900,28 @@ WorkerPrivate::ReportError(JSContext* aC
   ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message,
                                    filename, line, lineNumber,
                                    columnNumber, flags, errorNumber, exnType,
                                    mutedError, 0);
 
   mErrorHandlerRecursionCount--;
 }
 
+// static
+void
+WorkerPrivate::ReportErrorToConsole(const char* aMessage)
+{
+  WorkerPrivate* wp = nullptr;
+  if (!NS_IsMainThread()) {
+    wp = GetCurrentThreadWorkerPrivate();
+  }
+
+  ReportErrorToConsoleRunnable::Report(wp, aMessage);
+}
+
 int32_t
 WorkerPrivate::SetTimeout(JSContext* aCx,
                           dom::Function* aHandler,
                           const nsAString& aStringHandler,
                           int32_t aTimeout,
                           const Sequence<JS::Value>& aArguments,
                           bool aIsInterval,
                           ErrorResult& aRv)
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1124,16 +1124,19 @@ public:
                         const nsAString& aMessage);
 
   bool
   NotifyInternal(JSContext* aCx, Status aStatus);
 
   void
   ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
 
+  static void
+  ReportErrorToConsole(const char* aMessage);
+
   int32_t
   SetTimeout(JSContext* aCx,
              Function* aHandler,
              const nsAString& aStringHandler,
              int32_t aTimeout,
              const Sequence<JS::Value>& aArguments,
              bool aIsInterval,
              ErrorResult& aRv);