Bug 1167296 - patch 1 - ServiceWorkerManager::RemoveAll should use PBackground, r=nsm
authorAndrea Marchesini <amarchesini@mozilla.com>
Sun, 21 Jun 2015 12:17:58 +0100
changeset 280696 b00b2c78aa4af4c2d032e6542b696e45856911aa
parent 280695 b7653e3d5f919816b8e58750450ef505257027a8
child 280697 e47c1128e79b98f398c8a74dd21ed88b350a2e5d
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnsm
bugs1167296
milestone41.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 1167296 - patch 1 - ServiceWorkerManager::RemoveAll should use PBackground, r=nsm
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PContent.ipdl
dom/workers/PServiceWorkerManager.ipdl
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
dom/workers/ServiceWorkerManagerChild.cpp
dom/workers/ServiceWorkerManagerChild.h
dom/workers/ServiceWorkerManagerParent.cpp
dom/workers/ServiceWorkerManagerParent.h
dom/workers/ServiceWorkerManagerService.cpp
dom/workers/ServiceWorkerManagerService.h
dom/workers/ServiceWorkerRegistrar.cpp
dom/workers/ServiceWorkerRegistrar.h
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -28,17 +28,17 @@ interface nsIServiceWorkerInfo : nsISupp
   readonly attribute DOMString scope;
   readonly attribute DOMString scriptSpec;
   readonly attribute DOMString currentWorkerURL;
 
   readonly attribute DOMString activeCacheName;
   readonly attribute DOMString waitingCacheName;
 };
 
-[scriptable, builtinclass, uuid(5e112a42-df4c-4ae9-bc71-e6e681ab5f38)]
+[scriptable, builtinclass, uuid(d72bd950-967c-4642-bd34-7f688d9b624a)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -102,21 +102,16 @@ interface nsIServiceWorkerManager : nsIS
    * - All ServiceWorker instances change their state to redundant.
    * - Existing ServiceWorker instances handling fetches will keep running.
    * - All documents will immediately stop being controlled.
    * - Unregister jobs will be queued for all registrations.
    *   This eventually results in the registration being deleted from disk too.
    */
   void remove(in AUTF8String aHost);
 
-  /*
-   * Clear all registrations for all hosts. See remove().
-   */
-  void removeAll();
-
   // Testing
   DOMString getScopeForUrl(in nsIPrincipal aPrincipal, in DOMString aPath);
 
   // Note: This is meant to be used only by about:serviceworkers.
   //It returns an array of nsIServiceWorkerInfo.
   nsIArray getAllRegistrations();
 
   // Note: This is meant to be used only by about:serviceworkers.
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1249,26 +1249,16 @@ ContentChild::RecvRemoveServiceWorkerReg
 {
     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     if (swm) {
         swm->Remove(NS_ConvertUTF16toUTF8(aDomain));
     }
     return true;
 }
 
-bool
-ContentChild::RecvRemoveServiceWorkerRegistrations()
-{
-    nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
-    if (swm) {
-        swm->RemoveAll();
-    }
-    return true;
-}
-
 static CancelableTask* sFirstIdleTask;
 
 static void FirstIdle(void)
 {
     MOZ_ASSERT(sFirstIdleTask);
     sFirstIdleTask = nullptr;
     ContentChild::GetSingleton()->SendFirstIdle();
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -302,18 +302,16 @@ public:
     virtual bool RecvSpeakerManagerNotify() override;
 
     virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL) override;
 
     virtual bool RecvUpdateServiceWorkerRegistrations() override;
 
     virtual bool RecvRemoveServiceWorkerRegistrationsForDomain(const nsString& aDomain) override;
 
-    virtual bool RecvRemoveServiceWorkerRegistrations() override;
-
     virtual bool RecvNotifyVisited(const URIParams& aURI) override;
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId,
                                            const uint32_t& aMemoryAvailable) override;
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -503,18 +503,16 @@ child:
      * BidiKeyboard hosted by the parent
      */
     async BidiKeyboardNotify(bool isLangRTL);
 
     async UpdateServiceWorkerRegistrations();
 
     async RemoveServiceWorkerRegistrationsForDomain(nsString aDomain);
 
-    async RemoveServiceWorkerRegistrations();
-
     async DataStoreNotify(uint32_t aAppId, nsString aName,
                           nsString aManifestURL);
 
     /**
      * Dump this process's GC and CC logs to the provided files.
      *
      * For documentation on the other args, see dumpGCAndCCLogsToFile in
      * nsIMemoryInfoDumper.idl
--- a/dom/workers/PServiceWorkerManager.ipdl
+++ b/dom/workers/PServiceWorkerManager.ipdl
@@ -20,20 +20,23 @@ parent:
   Register(ServiceWorkerRegistrationData data);
 
   Unregister(PrincipalInfo principalInfo, nsString scope);
 
   PropagateSoftUpdate(OriginAttributes originAttributes,
                       nsString scope);
   PropagateUnregister(PrincipalInfo principalInfo, nsString scope);
 
+  PropagateRemoveAll();
+
   Shutdown();
 
 child:
   NotifyRegister(ServiceWorkerRegistrationData data);
   NotifySoftUpdate(OriginAttributes originAttributes, nsString scope);
   NotifyUnregister(PrincipalInfo principalInfo, nsString scope);
+  NotifyRemoveAll();
 
   __delete__();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -729,17 +729,17 @@ public:
 
   NS_IMETHOD Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     MOZ_ASSERT(swm);
 
-    swm->PropagateSoftUpdate(mOriginAttributes,mScope);
+    swm->PropagateSoftUpdate(mOriginAttributes, mScope);
     return NS_OK;
   }
 
 private:
   ~PropagateSoftUpdateRunnable()
   {}
 
   const OriginAttributes mOriginAttributes;
@@ -778,16 +778,38 @@ private:
   ~PropagateUnregisterRunnable()
   {}
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
   const nsString mScope;
 };
 
+class PropagateRemoveAllRunnable final : public nsRunnable
+{
+public:
+  PropagateRemoveAllRunnable()
+  {}
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    MOZ_ASSERT(swm);
+
+    swm->PropagateRemoveAll();
+    return NS_OK;
+  }
+
+private:
+  ~PropagateRemoveAllRunnable()
+  {}
+};
+
 } // anonymous namespace
 
 class ServiceWorkerRegisterJob final : public ServiceWorkerJob,
                                        public serviceWorkerScriptCache::CompareCallback
 {
   friend class ContinueInstallTask;
 
   nsCString mScope;
@@ -4334,22 +4356,36 @@ NS_IMETHODIMP
 ServiceWorkerManager::Remove(const nsACString& aHost)
 {
   AssertIsOnMainThread();
   mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal,
                                    &const_cast<nsACString&>(aHost));
   return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 ServiceWorkerManager::RemoveAll()
 {
   AssertIsOnMainThread();
   mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal, nullptr);
-  return NS_OK;
+}
+
+void
+ServiceWorkerManager::PropagateRemoveAll()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+
+  if (!mActor) {
+    nsRefPtr<nsIRunnable> runnable = new PropagateRemoveAllRunnable();
+    AppendPendingOperation(runnable);
+    return;
+  }
+
+  mActor->SendPropagateRemoveAll();
 }
 
 static PLDHashOperator
 UpdateEachRegistration(const nsACString& aKey,
                        ServiceWorkerRegistrationInfo* aInfo,
                        void* aUserArg) {
   auto This = static_cast<ServiceWorkerManager*>(aUserArg);
   MOZ_ASSERT(!aInfo->mScope.IsEmpty());
@@ -4389,26 +4425,26 @@ ServiceWorkerManager::UpdateAllRegistrat
 
 NS_IMETHODIMP
 ServiceWorkerManager::Observe(nsISupports* aSubject,
                               const char* aTopic,
                               const char16_t* aData)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
+  if (strcmp(aTopic, PURGE_SESSION_HISTORY) == 0) {
+    RemoveAll();
+    PropagateRemoveAll();
+    return NS_OK;
+  }
+
   nsAutoTArray<ContentParent*,1> children;
   ContentParent::GetAll(children);
 
-  if (strcmp(aTopic, PURGE_SESSION_HISTORY) == 0) {
-    for (uint32_t i = 0; i < children.Length(); i++) {
-      unused << children[i]->SendRemoveServiceWorkerRegistrations();
-    }
-
-    RemoveAll();
-  } else if (strcmp(aTopic, PURGE_DOMAIN_DATA) == 0) {
+  if (strcmp(aTopic, PURGE_DOMAIN_DATA) == 0) {
     nsAutoString domain(aData);
     for (uint32_t i = 0; i < children.Length(); i++) {
       unused << children[i]->SendRemoveServiceWorkerRegistrationsForDomain(domain);
     }
 
     Remove(NS_ConvertUTF16toUTF8(domain));
   } else if (strcmp(aTopic, WEBAPPS_CLEAR_DATA) == 0) {
     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -303,16 +303,22 @@ public:
 
   void
   SoftUpdate(const OriginAttributes& aOriginAttributes, const nsACString& aScope);
 
   void
   PropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
                       const nsAString& aScope);
 
+  void
+  PropagateRemoveAll();
+
+  void
+  RemoveAll();
+
   already_AddRefed<ServiceWorkerRegistrationInfo>
   GetRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope) const;
 
   ServiceWorkerRegistrationInfo*
   CreateNewRegistration(const nsCString& aScope, nsIPrincipal* aPrincipal);
 
   void
   RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
--- a/dom/workers/ServiceWorkerManagerChild.cpp
+++ b/dom/workers/ServiceWorkerManagerChild.cpp
@@ -62,11 +62,25 @@ ServiceWorkerManagerChild::RecvNotifyUnr
     return true;
   }
 
   nsresult rv = swm->Unregister(principal, nullptr, aScope);
   unused << NS_WARN_IF(NS_FAILED(rv));
   return true;
 }
 
+bool
+ServiceWorkerManagerChild::RecvNotifyRemoveAll()
+{
+  if (mShuttingDown) {
+    return true;
+  }
+
+  nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  MOZ_ASSERT(swm);
+
+  swm->RemoveAll();
+  return true;
+}
+
 } // workers namespace
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/ServiceWorkerManagerChild.h
+++ b/dom/workers/ServiceWorkerManagerChild.h
@@ -37,16 +37,18 @@ public:
                                                                        override;
 
   virtual bool RecvNotifySoftUpdate(const OriginAttributes& aOriginAttributes,
                                     const nsString& aScope) override;
 
   virtual bool RecvNotifyUnregister(const PrincipalInfo& aPrincipalInfo,
                                     const nsString& aScope) override;
 
+  virtual bool RecvNotifyRemoveAll() override;
+
 private:
   ServiceWorkerManagerChild()
     : mShuttingDown(false)
   {}
 
   ~ServiceWorkerManagerChild() {}
 
   bool mShuttingDown;
--- a/dom/workers/ServiceWorkerManagerParent.cpp
+++ b/dom/workers/ServiceWorkerManagerParent.cpp
@@ -252,16 +252,29 @@ ServiceWorkerManagerParent::RecvPropagat
     return false;
   }
 
   mService->PropagateUnregister(mID, aPrincipalInfo, aScope);
   return true;
 }
 
 bool
+ServiceWorkerManagerParent::RecvPropagateRemoveAll()
+{
+  AssertIsOnBackgroundThread();
+
+  if (NS_WARN_IF(!mService)) {
+    return false;
+  }
+
+  mService->PropagateRemoveAll(mID);
+  return true;
+}
+
+bool
 ServiceWorkerManagerParent::RecvShutdown()
 {
   AssertIsOnBackgroundThread();
 
   if (NS_WARN_IF(!mService)) {
     return false;
   }
 
--- a/dom/workers/ServiceWorkerManagerParent.h
+++ b/dom/workers/ServiceWorkerManagerParent.h
@@ -43,16 +43,18 @@ private:
                               const nsString& aScope) override;
 
   virtual bool RecvPropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
                                        const nsString& aScope) override;
 
   virtual bool RecvPropagateUnregister(const PrincipalInfo& aPrincipalInfo,
                                        const nsString& aScope) override;
 
+  virtual bool RecvPropagateRemoveAll() override;
+
   virtual bool RecvShutdown() override;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   nsRefPtr<ServiceWorkerManagerService> mService;
 
   // We use this ID in the Service in order to avoid the sending of messages to
   // ourself.
--- a/dom/workers/ServiceWorkerManagerService.cpp
+++ b/dom/workers/ServiceWorkerManagerService.cpp
@@ -222,16 +222,58 @@ UnregisterEnumerator(nsPtrHashKey<Servic
   } else {
     data->mParentFound = true;
 #endif
   }
 
   return PL_DHASH_NEXT;
 }
 
+struct MOZ_STACK_CLASS RemoveAllData final
+{
+  RemoveAllData(uint64_t aParentID)
+    : mParentID(aParentID)
+#ifdef DEBUG
+    , mParentFound(false)
+#endif
+  {
+    MOZ_COUNT_CTOR(RemoveAllData);
+  }
+
+  ~RemoveAllData()
+  {
+    MOZ_COUNT_DTOR(RemoveAllData);
+  }
+
+  const uint64_t mParentID;
+#ifdef DEBUG
+  bool mParentFound;
+#endif
+};
+
+PLDHashOperator
+RemoveAllEnumerator(nsPtrHashKey<ServiceWorkerManagerParent>* aKey, void* aPtr)
+{
+  AssertIsOnBackgroundThread();
+
+  auto* data = static_cast<RemoveAllData*>(aPtr);
+  ServiceWorkerManagerParent* parent = aKey->GetKey();
+  MOZ_ASSERT(parent);
+
+  if (parent->ID() != data->mParentID) {
+    unused << parent->SendNotifyRemoveAll();
+#ifdef DEBUG
+  } else {
+    data->mParentFound = true;
+#endif
+  }
+
+  return PL_DHASH_NEXT;
+}
+
 } // anonymous namespce
 
 void
 ServiceWorkerManagerService::PropagateRegistration(
                                            uint64_t aParentID,
                                            ServiceWorkerRegistrationData& aData)
 {
   AssertIsOnBackgroundThread();
@@ -280,11 +322,30 @@ ServiceWorkerManagerService::PropagateUn
   UnregisterData data(aPrincipalInfo, aScope, aParentID);
   mAgents.EnumerateEntries(UnregisterEnumerator, &data);
 
 #ifdef DEBUG
   MOZ_ASSERT(data.mParentFound);
 #endif
 }
 
+void
+ServiceWorkerManagerService::PropagateRemoveAll(uint64_t aParentID)
+{
+  AssertIsOnBackgroundThread();
+
+  nsRefPtr<dom::ServiceWorkerRegistrar> service =
+    dom::ServiceWorkerRegistrar::Get();
+  MOZ_ASSERT(service);
+
+  service->RemoveAll();
+
+  RemoveAllData data(aParentID);
+  mAgents.EnumerateEntries(RemoveAllEnumerator, &data);
+
+#ifdef DEBUG
+  MOZ_ASSERT(data.mParentFound);
+#endif
+}
+
 } // workers namespace
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/ServiceWorkerManagerService.h
+++ b/dom/workers/ServiceWorkerManagerService.h
@@ -44,16 +44,18 @@ public:
   void PropagateSoftUpdate(uint64_t aParentID,
                            const OriginAttributes& aOriginAttributes,
                            const nsAString& aScope);
 
   void PropagateUnregister(uint64_t aParentID,
                            const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
                            const nsAString& aScope);
 
+  void PropagateRemoveAll(uint64_t aParentID);
+
 private:
   ServiceWorkerManagerService();
   ~ServiceWorkerManagerService();
 
   nsTHashtable<nsPtrHashKey<ServiceWorkerManagerParent>> mAgents;
 };
 
 } // workers namespace
--- a/dom/workers/ServiceWorkerRegistrar.cpp
+++ b/dom/workers/ServiceWorkerRegistrar.cpp
@@ -209,16 +209,41 @@ ServiceWorkerRegistrar::UnregisterServic
   }
 
   if (deleted) {
     ScheduleSaveData();
   }
 }
 
 void
+ServiceWorkerRegistrar::RemoveAll()
+{
+  AssertIsOnBackgroundThread();
+
+  if (mShuttingDown) {
+    NS_WARNING("Failed to remove all the serviceWorkers during shutting down.");
+    return;
+  }
+
+  bool deleted = false;
+
+  {
+    MonitorAutoLock lock(mMonitor);
+    MOZ_ASSERT(mDataLoaded);
+
+    deleted = !mData.IsEmpty();
+    mData.Clear();
+  }
+
+  if (deleted) {
+    ScheduleSaveData();
+  }
+}
+
+void
 ServiceWorkerRegistrar::LoadData()
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!mDataLoaded);
 
   nsresult rv = ReadData();
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/workers/ServiceWorkerRegistrar.h
+++ b/dom/workers/ServiceWorkerRegistrar.h
@@ -49,16 +49,17 @@ public:
 
   static already_AddRefed<ServiceWorkerRegistrar> Get();
 
   void GetRegistrations(nsTArray<ServiceWorkerRegistrationData>& aValues);
 
   void RegisterServiceWorker(const ServiceWorkerRegistrationData& aData);
   void UnregisterServiceWorker(const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
                                const nsACString& aScope);
+  void RemoveAll();
 
 protected:
   // These methods are protected because we test this class using gTest
   // subclassing it.
   void LoadData();
   void SaveData();
 
   nsresult ReadData();