Bug 1540733 - Create a new IPCBlobInputStreamChild actor when migrating, r=baku
authorNika Layzell <nika@thelayzells.com>
Thu, 02 May 2019 16:18:51 +0000
changeset 472356 6de795fcf1fa66ba4275014bebd7eda321583d44
parent 472355 98a5645c05669d1ad56bf3d6f5f602869e477876
child 472357 5226ccdaaa9e639074be48dc73e5e69f591fa1b6
push id113004
push userrgurzau@mozilla.com
push dateFri, 03 May 2019 04:25:36 +0000
treeherdermozilla-inbound@a9d7796acb8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1540733
milestone68.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 1540733 - Create a new IPCBlobInputStreamChild actor when migrating, r=baku Differential Revision: https://phabricator.services.mozilla.com/D27970
dom/file/ipc/IPCBlobInputStreamChild.cpp
dom/file/ipc/IPCBlobInputStreamParent.cpp
dom/file/ipc/IPCBlobUtils.h
--- a/dom/file/ipc/IPCBlobInputStreamChild.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamChild.cpp
@@ -170,59 +170,75 @@ void IPCBlobInputStreamChild::ActorDestr
   bool migrating = false;
 
   {
     MutexAutoLock lock(mMutex);
     migrating = mState == eActiveMigrating;
     mState = migrating ? eInactiveMigrating : eInactive;
   }
 
-  if (migrating) {
-    // We were waiting for this! Now we can migrate the actor in the correct
-    // thread.
-    RefPtr<IPCBlobInputStreamThread> thread =
-        IPCBlobInputStreamThread::GetOrCreate();
-    MOZ_ASSERT(thread, "We cannot continue without DOMFile thread.");
-
-    ResetManager();
-    thread->MigrateActor(this);
+  if (!migrating) {
+    // Let's cleanup the workerRef and the pending operation queue.
+    Shutdown();
     return;
   }
-
-  // Let's cleanup the workerRef and the pending operation queue.
-  Shutdown();
 }
 
 IPCBlobInputStreamChild::ActorState IPCBlobInputStreamChild::State() {
   MutexAutoLock lock(mMutex);
   return mState;
 }
 
 already_AddRefed<IPCBlobInputStream> IPCBlobInputStreamChild::CreateStream() {
   bool shouldMigrate = false;
 
-  RefPtr<IPCBlobInputStream> stream = new IPCBlobInputStream(this);
+  RefPtr<IPCBlobInputStream> stream;
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mState == eInactive) {
       return nullptr;
     }
 
     // The stream is active but maybe it is not running in the DOM-File thread.
     // We should migrate it there.
     if (mState == eActive &&
         !IPCBlobInputStreamThread::IsOnFileEventTarget(mOwningEventTarget)) {
       MOZ_ASSERT(mStreams.IsEmpty());
+
       shouldMigrate = true;
       mState = eActiveMigrating;
-    }
+
+      RefPtr<IPCBlobInputStreamThread> thread =
+          IPCBlobInputStreamThread::GetOrCreate();
+      MOZ_ASSERT(thread, "We cannot continue without DOMFile thread.");
+
+      // Create a new actor object to connect to the target thread.
+      RefPtr<IPCBlobInputStreamChild> newActor =
+          new IPCBlobInputStreamChild(mID, mSize);
+      {
+        MutexAutoLock newActorLock(newActor->mMutex);
 
-    mStreams.AppendElement(stream);
+        // Move over our local state onto the new actor object.
+        newActor->mWorkerRef = mWorkerRef;
+        newActor->mState = eInactiveMigrating;
+        newActor->mPendingOperations.SwapElements(mPendingOperations);
+
+        // Create the actual stream object.
+        stream = new IPCBlobInputStream(newActor);
+        newActor->mStreams.AppendElement(stream);
+      }
+
+      // Perform the actual migration.
+      thread->MigrateActor(newActor);
+    } else {
+      stream = new IPCBlobInputStream(this);
+      mStreams.AppendElement(stream);
+    }
   }
 
   // Send__delete__ will call ActorDestroy(). mMutex cannot be locked at this
   // time.
   if (shouldMigrate) {
     Send__delete__(this);
   }
 
--- a/dom/file/ipc/IPCBlobInputStreamParent.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamParent.cpp
@@ -74,17 +74,17 @@ void IPCBlobInputStreamParent::ActorDest
   RefPtr<IPCBlobInputStreamParentCallback> callback;
   mCallback.swap(callback);
 
   RefPtr<IPCBlobInputStreamStorage> storage = IPCBlobInputStreamStorage::Get();
 
   if (mMigrating) {
     if (callback && storage) {
       // We need to assign this callback to the next parent.
-      IPCBlobInputStreamStorage::Get()->StoreCallback(mID, callback);
+      storage->StoreCallback(mID, callback);
     }
     return;
   }
 
   if (storage) {
     storage->ForgetStream(mID);
   }
 
--- a/dom/file/ipc/IPCBlobUtils.h
+++ b/dom/file/ipc/IPCBlobUtils.h
@@ -153,31 +153,31 @@
  *    they are used on special I/O threads).
  *
  * In order to avoid this, IPCBlobInputStreamChild are 'migrated' to a DOM-File
  * thread. This is done in this way:
  *
  * 1. If IPCBlobInputStreamChild actor is not already owned by DOM-File thread,
  *    it calls Send__delete__ in order to inform the parent side that we don't
  *    need this IPC channel on the current thread.
+ * 2. A new IPCBlobInputStreamChild is created. IPCBlobInputStreamThread is
+ *    used to assign this actor to the DOM-File thread.
+ *    IPCBlobInputStreamThread::GetOrCreate() creates the DOM-File thread if it
+ *    doesn't exist yet. Pending operations and IPCBlobInputStreams are moved
+ *    onto the new actor.
  * 3. IPCBlobInputStreamParent::Recv__delete__ is called on the parent side and
  *    the parent actor is deleted. Doing this we don't remove the UUID from
  *    IPCBlobInputStreamStorage.
- * 4. When IPCBlobInputStreamChild::ActorDestroy() is called, we are sure that
- *    the IPC channel is completely released. IPCBlobInputStreamThread is be
- *    used to assign IPCBlobInputStreamChild actor to the DOM-File thread.
- *    IPCBlobInputStreamThread::GetOrCreate() creates the DOM-File thread if it
- *    doesn't exist yet and it initializes PBackground on it if needed.
- * 5. IPCBlobInputStreamChild is reused on the DOM-File thread for the creation
- *    of a new IPCBlobInputStreamParent actor on the parent side. Doing this,
- *    IPCBlobInputStreamChild will now be owned by the DOM-File thread.
- * 6. When the new IPCBlobInputStreamParent actor is created, it will receive
+ * 4. The IPCBlobInputStream constructor is sent with the new
+ *    IPCBlobInputStreamChild actor, with the DOM-File thread's PBackground as
+ *    its manager.
+ * 5. When the new IPCBlobInputStreamParent actor is created, it will receive
  *    the same UUID of the previous parent actor. The nsIInputStream will be
  *    retrieved from IPCBlobInputStreamStorage.
- * 7. In order to avoid leaks, IPCBlobInputStreamStorage will monitor child
+ * 6. In order to avoid leaks, IPCBlobInputStreamStorage will monitor child
  *    processes and in case one of them dies, it will release the
  *    nsIInputStream objects belonging to that process.
  *
  * If any API wants to retrieve a 'real inputStream when the migration is in
  * progress, that operation is stored in a pending queue and processed at the
  * end of the migration.
  *
  * IPCBlob and nsIAsyncInputStream