diff --git a/dom/file/ipc/IPCBlobInputStream.cpp b/dom/file/ipc/IPCBlobInputStream.cpp index d8ffc091c755..29ea1f0ebc2b 100644 --- a/dom/file/ipc/IPCBlobInputStream.cpp +++ b/dom/file/ipc/IPCBlobInputStream.cpp @@ -915,5 +915,12 @@ void IPCBlobInputStream::LengthReady(int64_t aLength) { } } +void IPCBlobInputStream::ActorMigrated(IPCBlobInputStreamChild* aNewActor) { + MutexAutoLock lock(mMutex); + MOZ_ASSERT(mActor->Size() == aNewActor->Size()); + MOZ_ASSERT(mActor->ID() == aNewActor->ID()); + mActor = aNewActor; +} + } // namespace dom } // namespace mozilla diff --git a/dom/file/ipc/IPCBlobInputStream.h b/dom/file/ipc/IPCBlobInputStream.h index 5fb9747a003c..e0a797750c0b 100644 --- a/dom/file/ipc/IPCBlobInputStream.h +++ b/dom/file/ipc/IPCBlobInputStream.h @@ -78,6 +78,8 @@ class IPCBlobInputStream final : public nsIAsyncInputStream, return nullptr; } + void ActorMigrated(IPCBlobInputStreamChild* aNewActor); + private: ~IPCBlobInputStream(); diff --git a/dom/file/ipc/IPCBlobInputStreamChild.cpp b/dom/file/ipc/IPCBlobInputStreamChild.cpp index 84fbe8d33120..acfd4e4e60e2 100644 --- a/dom/file/ipc/IPCBlobInputStreamChild.cpp +++ b/dom/file/ipc/IPCBlobInputStreamChild.cpp @@ -10,6 +10,7 @@ #include "mozilla/ipc/IPCStreamUtils.h" #include "mozilla/dom/WorkerCommon.h" #include "mozilla/dom/WorkerRef.h" +#include "mozilla/ipc/PBackgroundChild.h" namespace mozilla { namespace dom { @@ -182,7 +183,6 @@ void IPCBlobInputStreamChild::ActorDestroy( IPCBlobInputStreamThread::GetOrCreate(); MOZ_ASSERT(thread, "We cannot continue without DOMFile thread."); - ResetManager(); thread->MigrateActor(this); return; } @@ -386,14 +386,41 @@ mozilla::ipc::IPCResult IPCBlobInputStreamChild::RecvLengthReady( return IPC_OK(); } -void IPCBlobInputStreamChild::Migrated() { + +void IPCBlobInputStreamChild::MigrateTo(PBackgroundChild* aManager) { MutexAutoLock lock(mMutex); MOZ_ASSERT(mState == eInactiveMigrating); - mWorkerRef = nullptr; + // Construct the replacement actor, sending the IPC constructor. The reference + // taken will be freed by DeallocPIPCBlobInputStreamConstructor. + RefPtr actor = + new IPCBlobInputStreamChild(mID, mSize); + if (!aManager->SendPIPCBlobInputStreamConstructor(do_AddRef(actor).take(), + mID, mSize)) { + return; + } + + actor->MigratedFrom(this); + + // Finally, complete teardown of the old actor. + MOZ_ASSERT(mStreams.IsEmpty() && mPendingOperations.IsEmpty()); + mWorkerRef = nullptr; + mState = eInactive; +} + +void IPCBlobInputStreamChild::MigratedFrom(IPCBlobInputStreamChild* aOldActor) { + MutexAutoLock lock(mMutex); + aOldActor->mMutex.AssertCurrentThreadOwns(); - mOwningEventTarget = GetCurrentThreadSerialEventTarget(); MOZ_ASSERT(IPCBlobInputStreamThread::IsOnFileEventTarget(mOwningEventTarget)); + MOZ_ASSERT(mState == eActive); + + // Take streams & pending operations from |aOldActor|. + mStreams.SwapElements(aOldActor->mStreams); + mPendingOperations.SwapElements(aOldActor->mPendingOperations); + for (auto* stream : mStreams) { + stream->ActorMigrated(this); + } // Maybe we have no reasons to keep this actor alive. if (mStreams.IsEmpty()) { @@ -402,8 +429,6 @@ void IPCBlobInputStreamChild::Migrated() { return; } - mState = eActive; - // Let's processing the pending operations. We need a stream for each pending // operation. for (uint32_t i = 0; i < mPendingOperations.Length(); ++i) { diff --git a/dom/file/ipc/IPCBlobInputStreamChild.h b/dom/file/ipc/IPCBlobInputStreamChild.h index 3e0b28bc59f5..d031a182a772 100644 --- a/dom/file/ipc/IPCBlobInputStreamChild.h +++ b/dom/file/ipc/IPCBlobInputStreamChild.h @@ -64,11 +64,13 @@ class IPCBlobInputStreamChild final void Shutdown(); - void Migrated(); + void MigrateTo(PBackgroundChild* aManager); private: ~IPCBlobInputStreamChild(); + void MigratedFrom(IPCBlobInputStreamChild* aOldActor); + // Raw pointers because these streams keep this actor alive. When the last // stream is unregister, the actor will be deleted. This list is protected by // mutex. diff --git a/dom/file/ipc/IPCBlobInputStreamParent.cpp b/dom/file/ipc/IPCBlobInputStreamParent.cpp index 6f0c6a6cd2cd..73431e054b98 100644 --- a/dom/file/ipc/IPCBlobInputStreamParent.cpp +++ b/dom/file/ipc/IPCBlobInputStreamParent.cpp @@ -79,7 +79,7 @@ void IPCBlobInputStreamParent::ActorDestroy( 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; } diff --git a/dom/file/ipc/IPCBlobInputStreamThread.cpp b/dom/file/ipc/IPCBlobInputStreamThread.cpp index 7b4e59c116c7..18cc3ac2e7d9 100644 --- a/dom/file/ipc/IPCBlobInputStreamThread.cpp +++ b/dom/file/ipc/IPCBlobInputStreamThread.cpp @@ -47,23 +47,13 @@ class MigrateActorRunnable final : public Runnable { NS_IMETHOD Run() override { - MOZ_ASSERT(mActor->State() == IPCBlobInputStreamChild::eInactiveMigrating); - PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); if (!actorChild) { return NS_OK; } - if (actorChild->SendPIPCBlobInputStreamConstructor(mActor, mActor->ID(), - mActor->Size())) { - // We need manually to increase the reference for this actor because the - // IPC allocator method is not triggered. The Release() is called by IPDL - // when the actor is deleted. - mActor.get()->AddRef(); - mActor->Migrated(); - } - + mActor->MigrateTo(actorChild); return NS_OK; } diff --git a/dom/file/ipc/IPCBlobUtils.h b/dom/file/ipc/IPCBlobUtils.h index 6c436736fd62..15604fa07298 100644 --- a/dom/file/ipc/IPCBlobUtils.h +++ b/dom/file/ipc/IPCBlobUtils.h @@ -166,9 +166,10 @@ * 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. + * 5. A new IPCBlobInputStreamChild is created on the DOM-File thread for the + * creation of a new IPCBlobInputStreamParent actor on the parent side. + * Pending operations and IPCBlobInputStreams are moved onto the new actor, + * and back references are updated. * 6. 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.