Bug 1366316 - Separate thread for IPCBlobInputStream actors - part 4 - monitoring child processes, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 31 May 2017 07:41:11 +0200
changeset 361519 3965a5c72ea35aede1a3db86556713fbc85b6d84
parent 361518 c1b48496a0f39423b97304c01d855f0f361969b3
child 361520 fd22c45d4adaf340a733457443a686bd136012d5
push id31933
push userryanvm@gmail.com
push dateWed, 31 May 2017 18:33:05 +0000
treeherdermozilla-central@94906c37940c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1366316
milestone55.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 1366316 - Separate thread for IPCBlobInputStream actors - part 4 - monitoring child processes, r=smaug
dom/file/ipc/IPCBlobInputStreamParent.cpp
dom/file/ipc/IPCBlobInputStreamParent.h
dom/file/ipc/IPCBlobInputStreamStorage.cpp
dom/file/ipc/IPCBlobInputStreamStorage.h
dom/file/ipc/IPCBlobUtils.cpp
ipc/glue/BackgroundImpl.cpp
ipc/glue/BackgroundParent.h
--- a/dom/file/ipc/IPCBlobInputStreamParent.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamParent.cpp
@@ -10,28 +10,28 @@
 #include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 template<typename M>
 /* static */ IPCBlobInputStreamParent*
 IPCBlobInputStreamParent::Create(nsIInputStream* aInputStream, uint64_t aSize,
-                                 nsresult* aRv, M* aManager)
+                                 uint64_t aChildID, nsresult* aRv, M* aManager)
 {
   MOZ_ASSERT(aInputStream);
   MOZ_ASSERT(aRv);
 
   nsID id;
   *aRv = nsContentUtils::GenerateUUIDInPlace(id);
   if (NS_WARN_IF(NS_FAILED(*aRv))) {
     return nullptr;
   }
 
-  IPCBlobInputStreamStorage::Get()->AddStream(aInputStream, id);
+  IPCBlobInputStreamStorage::Get()->AddStream(aInputStream, id, aChildID);
 
   return new IPCBlobInputStreamParent(id, aSize, aManager);
 }
 
 /* static */ IPCBlobInputStreamParent*
 IPCBlobInputStreamParent::Create(const nsID& aID, uint64_t aSize,
                                  PBackgroundParent* aManager)
 {
--- a/dom/file/ipc/IPCBlobInputStreamParent.h
+++ b/dom/file/ipc/IPCBlobInputStreamParent.h
@@ -31,18 +31,18 @@ class IPCBlobInputStreamParent final
   : public mozilla::ipc::PIPCBlobInputStreamParent
 {
 public:
   // The size of the inputStream must be passed as argument in order to avoid
   // the use of nsIInputStream::Available() which could open a fileDescriptor in
   // case the stream is a nsFileStream.
   template<typename M>
   static IPCBlobInputStreamParent*
-  Create(nsIInputStream* aInputStream, uint64_t aSize, nsresult* aRv,
-         M* aManager);
+  Create(nsIInputStream* aInputStream, uint64_t aSize,
+         uint64_t aChildID, nsresult* aRv, M* aManager);
 
   static IPCBlobInputStreamParent*
   Create(const nsID& aID, uint64_t aSize,
          mozilla::ipc::PBackgroundParent* aManager);
 
   void
   ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
 
--- a/dom/file/ipc/IPCBlobInputStreamStorage.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamStorage.cpp
@@ -1,29 +1,41 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IPCBlobInputStreamStorage.h"
 
-#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
+#include "nsIPropertyBag2.h"
 #include "nsStreamUtils.h"
 
 namespace mozilla {
+
+using namespace hal;
+
 namespace dom {
 
 namespace {
 StaticMutex gMutex;
 StaticRefPtr<IPCBlobInputStreamStorage> gStorage;
 }
 
+NS_INTERFACE_MAP_BEGIN(IPCBlobInputStreamStorage)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(IPCBlobInputStreamStorage)
+NS_IMPL_RELEASE(IPCBlobInputStreamStorage)
+
 IPCBlobInputStreamStorage::IPCBlobInputStreamStorage()
 {}
 
 IPCBlobInputStreamStorage::~IPCBlobInputStreamStorage()
 {}
 
 /* static */ IPCBlobInputStreamStorage*
 IPCBlobInputStreamStorage::Get()
@@ -32,27 +44,73 @@ IPCBlobInputStreamStorage::Get()
 }
 
 /* static */ void
 IPCBlobInputStreamStorage::Initialize()
 {
   MOZ_ASSERT(!gStorage);
 
   gStorage = new IPCBlobInputStreamStorage();
-  ClearOnShutdown(&gStorage);
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->AddObserver(gStorage, "xpcom-shutdown", false);
+    obs->AddObserver(gStorage, "ipc:content-shutdown", false);
+  }
+}
+
+NS_IMETHODIMP
+IPCBlobInputStreamStorage::Observe(nsISupports* aSubject, const char* aTopic,
+                                   const char16_t* aData)
+{
+  if (!strcmp(aTopic, "xpcom-shutdown")) {
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->RemoveObserver(this, "xpcom-shutdown");
+      obs->RemoveObserver(this, "ipc:content-shutdown");
+    }
+
+    gStorage = nullptr;
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
+
+  nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
+  if (NS_WARN_IF(!props)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
+  props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
+  if (NS_WARN_IF(childID == CONTENT_PROCESS_ID_UNKNOWN)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mozilla::StaticMutexAutoLock lock(gMutex);
+
+  for (auto iter = mStorage.Iter(); !iter.Done(); iter.Next()) {
+    if (iter.Data()->mChildID == childID) {
+      iter.Remove();
+    }
+  }
+
+  return NS_OK;
 }
 
 void
 IPCBlobInputStreamStorage::AddStream(nsIInputStream* aInputStream,
-                                     const nsID& aID)
+                                     const nsID& aID,
+                                     uint64_t aChildID)
 {
   MOZ_ASSERT(aInputStream);
 
   StreamData* data = new StreamData();
   data->mInputStream = aInputStream;
+  data->mChildID = aChildID;
 
   mozilla::StaticMutexAutoLock lock(gMutex);
   mStorage.Put(aID, data);
 }
 
 void
 IPCBlobInputStreamStorage::ForgetStream(const nsID& aID)
 {
--- a/dom/file/ipc/IPCBlobInputStreamStorage.h
+++ b/dom/file/ipc/IPCBlobInputStreamStorage.h
@@ -4,40 +4,41 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ipc_IPCBlobInputStreamStorage_h
 #define mozilla_dom_ipc_IPCBlobInputStreamStorage_h
 
 #include "mozilla/RefPtr.h"
 #include "nsClassHashtable.h"
-#include "nsISupportsImpl.h"
+#include "nsIObserver.h"
 
 class nsIInputStream;
 struct nsID;
 
 namespace mozilla {
 namespace dom {
 
 class IPCBlobInputStreamParentCallback;
 
-class IPCBlobInputStreamStorage final
+class IPCBlobInputStreamStorage final : public nsIObserver
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPCBlobInputStreamStorage);
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOBSERVER
 
   // This initializes the singleton and it must be called on the main-thread.
   static void
   Initialize();
 
   static IPCBlobInputStreamStorage*
   Get();
 
   void
-  AddStream(nsIInputStream* aInputStream, const nsID& aID);
+  AddStream(nsIInputStream* aInputStream, const nsID& aID, uint64_t aChildID);
 
   void
   ForgetStream(const nsID& aID);
 
   void
   GetStream(const nsID& aID, nsIInputStream** aInputStream);
 
   void
@@ -49,16 +50,20 @@ public:
 private:
   IPCBlobInputStreamStorage();
   ~IPCBlobInputStreamStorage();
 
   struct StreamData
   {
     nsCOMPtr<nsIInputStream> mInputStream;
     RefPtr<IPCBlobInputStreamParentCallback> mCallback;
+
+    // This is the Process ID connected with this inputStream. We need to store
+    // this information in order to delete it if the child crashes/shutdowns.
+    uint64_t mChildID;
   };
 
   nsClassHashtable<nsIDHashKey, StreamData> mStorage;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/file/ipc/IPCBlobUtils.cpp
+++ b/dom/file/ipc/IPCBlobUtils.cpp
@@ -6,16 +6,17 @@
 
 #include "IPCBlobUtils.h"
 #include "IPCBlobInputStream.h"
 #include "IPCBlobInputStreamChild.h"
 #include "IPCBlobInputStreamParent.h"
 #include "IPCBlobInputStreamStorage.h"
 #include "mozilla/dom/IPCBlob.h"
 #include "mozilla/dom/nsIContentParent.h"
+#include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/IPCStreamUtils.h"
 #include "StreamBlobImpl.h"
 #include "prtime.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
@@ -74,24 +75,25 @@ Deserialize(const IPCBlob& aIPCBlob)
   blobImpl->SetFileId(aIPCBlob.fileId());
 
   return blobImpl.forget();
 }
 
 template<typename M>
 nsresult
 SerializeInputStreamParent(nsIInputStream* aInputStream, uint64_t aSize,
-                           IPCBlob& aIPCBlob, M* aManager)
+                           uint64_t aChildID, IPCBlob& aIPCBlob, M* aManager)
 {
   // Parent to Child we always send a IPCBlobInputStream.
   MOZ_ASSERT(XRE_IsParentProcess());
 
   nsresult rv;
   IPCBlobInputStreamParent* parentActor =
-    IPCBlobInputStreamParent::Create(aInputStream, aSize, &rv, aManager);
+    IPCBlobInputStreamParent::Create(aInputStream, aSize, aChildID, &rv,
+                                     aManager);
   if (!parentActor) {
     return rv;
   }
 
   if (!aManager->SendPIPCBlobInputStreamConstructor(parentActor,
                                                     parentActor->ID(),
                                                     parentActor->Size())) {
     return NS_ERROR_FAILURE;
@@ -112,42 +114,72 @@ SerializeInputStreamChild(nsIInputStream
   }
 
   aIPCBlob.inputStream() = ipcStream.TakeValue();
   return NS_OK;
 }
 
 nsresult
 SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
-                     IPCBlob& aIPCBlob, nsIContentParent* aManager)
+                     uint64_t aChildID, IPCBlob& aIPCBlob,
+                     nsIContentParent* aManager)
 {
-  return SerializeInputStreamParent(aInputStream, aSize, aIPCBlob, aManager);
+  return SerializeInputStreamParent(aInputStream, aSize, aChildID, aIPCBlob,
+                                    aManager);
 }
 
 nsresult
 SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
-                     IPCBlob& aIPCBlob, PBackgroundParent* aManager)
+                     uint64_t aChildID, IPCBlob& aIPCBlob,
+                     PBackgroundParent* aManager)
 {
-  return SerializeInputStreamParent(aInputStream, aSize, aIPCBlob, aManager);
+  return SerializeInputStreamParent(aInputStream, aSize, aChildID, aIPCBlob,
+                                    aManager);
 }
 
 nsresult
 SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
-                     IPCBlob& aIPCBlob, nsIContentChild* aManager)
+                     uint64_t aChildID, IPCBlob& aIPCBlob,
+                     nsIContentChild* aManager)
 {
   return SerializeInputStreamChild(aInputStream, aIPCBlob, aManager);
 }
 
 nsresult
 SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
-                     IPCBlob& aIPCBlob, PBackgroundChild* aManager)
+                     uint64_t aChildID, IPCBlob& aIPCBlob,
+                     PBackgroundChild* aManager)
 {
   return SerializeInputStreamChild(aInputStream, aIPCBlob, aManager);
 }
 
+uint64_t
+ChildIDFromManager(nsIContentParent* aManager)
+{
+  return aManager->ChildID();
+}
+
+uint64_t
+ChildIDFromManager(PBackgroundParent* aManager)
+{
+  return BackgroundParent::GetChildID(aManager);
+}
+
+uint64_t
+ChildIDFromManager(nsIContentChild* aManager)
+{
+  return 0;
+}
+
+uint64_t
+ChildIDFromManager(PBackgroundChild* aManager)
+{
+  return 0;
+}
+
 template<typename M>
 nsresult
 SerializeInternal(BlobImpl* aBlobImpl, M* aManager, IPCBlob& aIPCBlob)
 {
   MOZ_ASSERT(aBlobImpl);
 
   nsAutoString value;
   aBlobImpl->GetType(value);
@@ -189,17 +221,18 @@ SerializeInternal(BlobImpl* aBlobImpl, M
   aIPCBlob.fileId() = aBlobImpl->GetFileId();
 
   nsCOMPtr<nsIInputStream> inputStream;
   aBlobImpl->GetInternalStream(getter_AddRefs(inputStream), rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
-  rv = SerializeInputStream(inputStream, aIPCBlob.size(), aIPCBlob, aManager);
+  rv = SerializeInputStream(inputStream, aIPCBlob.size(),
+                            ChildIDFromManager(aManager), aIPCBlob, aManager);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -208,16 +208,20 @@ private:
   static already_AddRefed<ContentParent>
   GetContentParent(PBackgroundParent* aBackgroundActor);
 
   // Forwarded from BackgroundParent.
   static intptr_t
   GetRawContentParentForComparison(PBackgroundParent* aBackgroundActor);
 
   // Forwarded from BackgroundParent.
+  static uint64_t
+  GetChildID(PBackgroundParent* aBackgroundActor);
+
+  // Forwarded from BackgroundParent.
   static bool
   Alloc(ContentParent* aContent,
         Endpoint<PBackgroundParent>&& aEndpoint);
 
   static bool
   CreateBackgroundThread();
 
   static void
@@ -812,16 +816,23 @@ BackgroundParent::GetContentParent(PBack
 intptr_t
 BackgroundParent::GetRawContentParentForComparison(
                                             PBackgroundParent* aBackgroundActor)
 {
   return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
 }
 
 // static
+uint64_t
+BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor)
+{
+  return ParentImpl::GetChildID(aBackgroundActor);
+}
+
+// static
 bool
 BackgroundParent::Alloc(ContentParent* aContent,
                         Endpoint<PBackgroundParent>&& aEndpoint)
 {
   return ParentImpl::Alloc(aContent, Move(aEndpoint));
 }
 
 // -----------------------------------------------------------------------------
@@ -964,16 +975,36 @@ ParentImpl::GetRawContentParentForCompar
                "called!");
     return intptr_t(-1);
   }
 
   return intptr_t(static_cast<nsIContentParent*>(actor->mContent.get()));
 }
 
 // static
+uint64_t
+ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aBackgroundActor);
+
+  auto actor = static_cast<ParentImpl*>(aBackgroundActor);
+  if (actor->mActorDestroyed) {
+    MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
+    return 0;
+  }
+
+  if (actor->mContent) {
+    return actor->mContent->ChildID();
+  }
+
+  return 0;
+}
+
+// static
 bool
 ParentImpl::Alloc(ContentParent* aContent,
                   Endpoint<PBackgroundParent>&& aEndpoint)
 {
   AssertIsInMainProcess();
   AssertIsOnMainThread();
   MOZ_ASSERT(aEndpoint.IsValid());
 
--- a/ipc/glue/BackgroundParent.h
+++ b/ipc/glue/BackgroundParent.h
@@ -59,16 +59,19 @@ public:
 
   // Get a value that represents the ContentParent associated with the parent
   // actor for comparison. The value is not guaranteed to uniquely identify the
   // ContentParent after the ContentParent has died. This function may only be
   // called on the background thread.
   static intptr_t
   GetRawContentParentForComparison(PBackgroundParent* aBackgroundActor);
 
+  static uint64_t
+  GetChildID(PBackgroundParent* aBackgroundActor);
+
 private:
   // Only called by ContentParent for cross-process actors.
   static bool
   Alloc(ContentParent* aContent,
         Endpoint<PBackgroundParent>&& aEndpoint);
 };
 
 // Implemented in BackgroundImpl.cpp.