Bug 1152048 - Send wakeup notification asynchronously to avoid reentrancy issues. r=bagder
authorNicholas Hurley <hurley@todesschaf.org>
Fri, 31 Jul 2015 13:39:48 -0700
changeset 287629 a0582ac1d92e3484975e8dd6144cf42f8ad27d4b
parent 287628 cd1d76c2f219987ad981e1f3e9ac76845a9962a2
child 287630 dff0fcf398a1359440ee7939abad80151a2dcdc3
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbagder
bugs1152048
milestone42.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 1152048 - Send wakeup notification asynchronously to avoid reentrancy issues. r=bagder
netwerk/base/nsIIOService.idl
netwerk/base/nsIOService.cpp
--- a/netwerk/base/nsIIOService.idl
+++ b/netwerk/base/nsIIOService.idl
@@ -270,18 +270,24 @@ interface nsIAppOfflineInfo : nsISupport
 
 /**
  * When network:app-offline-status-changed is fired,
  * the 'Subject' argument is a nsIOfflineAppInfo.
  */
 #define NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC "network:app-offline-status-changed"
 %}
 
-[builtinclass, uuid(cd66ffef-3bc3-40de-841a-e2dcbea213a2)]
+[builtinclass, uuid(6633c0bf-d97a-428f-8ece-cb6a655fb95a)]
 interface nsIIOServiceInternal : nsISupports
 {
     /**
      * This is an internal method that should only be called from ContentChild
      * in order to pass the connectivity state from the chrome process to the
      * content process. It throws if called outside the content process.
      */
     void SetConnectivity(in boolean connectivity);
+
+    /**
+     * An internal method to asynchronously run our notifications that happen
+     * when we wake from sleep
+     */
+    void NotifyWakeup();
 };
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -1357,16 +1357,56 @@ nsIOService::EnumerateWifiAppsChangingSt
 {
     EnumeratorParams *params = reinterpret_cast<EnumeratorParams*>(aUserArg);
     if (aValue == nsIAppOfflineInfo::WIFI_ONLY) {
         params->service->NotifyAppOfflineStatus(aKey, params->status);
     }
     return PL_DHASH_NEXT;
 }
 
+class
+nsWakeupNotifier : public nsRunnable
+{
+public:
+    explicit nsWakeupNotifier(nsIIOServiceInternal *ioService)
+        :mIOService(ioService)
+    { }
+
+    NS_IMETHOD Run()
+    {
+        return mIOService->NotifyWakeup();
+    }
+
+private:
+    virtual ~nsWakeupNotifier() { }
+    nsCOMPtr<nsIIOServiceInternal> mIOService;
+};
+
+NS_IMETHODIMP
+nsIOService::NotifyWakeup()
+{
+    nsCOMPtr<nsIObserverService> observerService =
+        mozilla::services::GetObserverService();
+
+    NS_ASSERTION(observerService, "The observer service should not be null");
+
+    if (observerService && mNetworkNotifyChanged) {
+        (void)observerService->
+            NotifyObservers(nullptr,
+                            NS_NETWORK_LINK_TOPIC,
+                            MOZ_UTF16(NS_NETWORK_LINK_DATA_CHANGED));
+    }
+
+    if (mCaptivePortalService) {
+        mCaptivePortalService->RecheckCaptivePortal();
+    }
+
+    return NS_OK;
+}
+
 // nsIObserver interface
 NS_IMETHODIMP
 nsIOService::Observe(nsISupports *subject,
                      const char *topic,
                      const char16_t *data)
 {
     if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
         nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject);
@@ -1409,31 +1449,20 @@ nsIOService::Observe(nsISupports *subjec
         }
 
         // Break circular reference.
         mProxyService = nullptr;
     } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
         OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
     } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
         // coming back alive from sleep
-        nsCOMPtr<nsIObserverService> observerService =
-            mozilla::services::GetObserverService();
-
-        NS_ASSERTION(observerService, "The observer service should not be null");
-
-        if (observerService && mNetworkNotifyChanged) {
-            (void)observerService->
-                NotifyObservers(nullptr,
-                                NS_NETWORK_LINK_TOPIC,
-                                MOZ_UTF16(NS_NETWORK_LINK_DATA_CHANGED));
-        }
-
-        if (mCaptivePortalService) {
-            mCaptivePortalService->RecheckCaptivePortal();
-        }
+        // this indirection brought to you by:
+        // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19
+        nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this);
+        NS_DispatchToMainThread(wakeupNotifier);
     } else if (!strcmp(topic, kNetworkActiveChanged)) {
 #ifdef MOZ_WIDGET_GONK
         if (IsNeckoChild()) {
           return NS_OK;
         }
         nsCOMPtr<nsINetworkInfo> interface = do_QueryInterface(subject);
         if (!interface) {
             return NS_ERROR_FAILURE;