mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 1359718 - Get rid of PBlob - part 1 - Remove PBlobStream, r=smaug, r=kanru
This commit is contained in:
parent
28479706ea
commit
bc8f9a2827
@ -22,8 +22,6 @@
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
#include "mozilla/dom/nsIContentParent.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/dom/PBlobStreamChild.h"
|
||||
#include "mozilla/dom/PBlobStreamParent.h"
|
||||
#include "mozilla/dom/indexedDB/FileSnapshot.h"
|
||||
#include "mozilla/dom/IndexedDatabaseManager.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
@ -562,32 +560,6 @@ private:
|
||||
|
||||
namespace {
|
||||
|
||||
class InputStreamChild final
|
||||
: public PBlobStreamChild
|
||||
{
|
||||
RefPtr<RemoteInputStream> mRemoteStream;
|
||||
|
||||
public:
|
||||
explicit
|
||||
InputStreamChild(RemoteInputStream* aRemoteStream)
|
||||
: mRemoteStream(aRemoteStream)
|
||||
{
|
||||
MOZ_ASSERT(aRemoteStream);
|
||||
aRemoteStream->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
InputStreamChild()
|
||||
{ }
|
||||
|
||||
~InputStreamChild() override = default;
|
||||
|
||||
private:
|
||||
// This method is only called by the IPDL message machinery.
|
||||
mozilla::ipc::IPCResult
|
||||
Recv__delete__(const InputStreamParams& aParams,
|
||||
const OptionalFileDescriptorSet& aFDs) override;
|
||||
};
|
||||
|
||||
struct MOZ_STACK_CLASS CreateBlobImplMetadata final
|
||||
{
|
||||
nsString mContentType;
|
||||
@ -1018,7 +990,7 @@ RemoteInputStream::BlockAndWaitForStream()
|
||||
InputStreamParams params;
|
||||
OptionalFileDescriptorSet optionalFDs;
|
||||
|
||||
mActor->SendBlobStreamSync(mStart, mLength, ¶ms, &optionalFDs);
|
||||
// This method is broken now...
|
||||
|
||||
nsTArray<FileDescriptor> fds;
|
||||
OptionalFileDescriptorSetToFDs(optionalFDs, fds);
|
||||
@ -1376,88 +1348,6 @@ RemoteInputStream::BlockAndGetInternalStream()
|
||||
return mStream;
|
||||
}
|
||||
|
||||
class InputStreamParent final
|
||||
: public PBlobStreamParent
|
||||
{
|
||||
typedef mozilla::ipc::InputStreamParams InputStreamParams;
|
||||
typedef mozilla::dom::OptionalFileDescriptorSet OptionalFileDescriptorSet;
|
||||
|
||||
bool* mSyncLoopGuard;
|
||||
InputStreamParams* mParams;
|
||||
OptionalFileDescriptorSet* mFDs;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
InputStreamParent()
|
||||
: mSyncLoopGuard(nullptr)
|
||||
, mParams(nullptr)
|
||||
, mFDs(nullptr)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(InputStreamParent);
|
||||
}
|
||||
|
||||
InputStreamParent(bool* aSyncLoopGuard,
|
||||
InputStreamParams* aParams,
|
||||
OptionalFileDescriptorSet* aFDs)
|
||||
: mSyncLoopGuard(aSyncLoopGuard)
|
||||
, mParams(aParams)
|
||||
, mFDs(aFDs)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aSyncLoopGuard);
|
||||
MOZ_ASSERT(!*aSyncLoopGuard);
|
||||
MOZ_ASSERT(aParams);
|
||||
MOZ_ASSERT(aFDs);
|
||||
|
||||
MOZ_COUNT_CTOR(InputStreamParent);
|
||||
}
|
||||
|
||||
~InputStreamParent() override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(InputStreamParent);
|
||||
}
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(InputStreamParent);
|
||||
}
|
||||
|
||||
bool
|
||||
Destroy(const InputStreamParams& aParams,
|
||||
const OptionalFileDescriptorSet& aFDs)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mSyncLoopGuard) {
|
||||
MOZ_ASSERT(!*mSyncLoopGuard);
|
||||
|
||||
*mSyncLoopGuard = true;
|
||||
*mParams = aParams;
|
||||
*mFDs = aFDs;
|
||||
|
||||
// We're not a live actor so manage the memory ourselves.
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will be destroyed by BlobParent::DeallocPBlobStreamParent.
|
||||
return PBlobStreamParent::Send__delete__(this, aParams, aFDs);
|
||||
}
|
||||
|
||||
private:
|
||||
// This method is only called by the IPDL message machinery.
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override
|
||||
{
|
||||
// Nothing needs to be done here.
|
||||
}
|
||||
};
|
||||
StaticAutoPtr<BlobParent::IDTable> BlobParent::sIDTable;
|
||||
StaticAutoPtr<Mutex> BlobParent::sIDTableMutex;
|
||||
|
||||
@ -1561,244 +1451,6 @@ private:
|
||||
bool aIgnoreProcessID);
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* BlobParent::OpenStreamRunnable Declaration
|
||||
******************************************************************************/
|
||||
|
||||
// Each instance of this class will be dispatched to the network stream thread
|
||||
// pool to run the first time where it will open the file input stream. It will
|
||||
// then dispatch itself back to the owning thread to send the child process its
|
||||
// response (assuming that the child has not crashed). The runnable will then
|
||||
// dispatch itself to the thread pool again in order to close the file input
|
||||
// stream.
|
||||
class BlobParent::OpenStreamRunnable final
|
||||
: public Runnable
|
||||
{
|
||||
friend class nsRevocableEventPtr<OpenStreamRunnable>;
|
||||
|
||||
// Only safe to access these pointers if mRevoked is false!
|
||||
BlobParent* mBlobActor;
|
||||
InputStreamParent* mStreamActor;
|
||||
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
|
||||
nsCOMPtr<nsIEventTarget> mActorTarget;
|
||||
nsCOMPtr<nsIThread> mIOTarget;
|
||||
|
||||
bool mRevoked;
|
||||
bool mClosing;
|
||||
|
||||
public:
|
||||
OpenStreamRunnable(BlobParent* aBlobActor,
|
||||
InputStreamParent* aStreamActor,
|
||||
nsIInputStream* aStream,
|
||||
nsIIPCSerializableInputStream* aSerializable,
|
||||
nsIThread* aIOTarget)
|
||||
: mBlobActor(aBlobActor)
|
||||
, mStreamActor(aStreamActor)
|
||||
, mStream(aStream)
|
||||
, mSerializable(aSerializable)
|
||||
, mIOTarget(aIOTarget)
|
||||
, mRevoked(false)
|
||||
, mClosing(false)
|
||||
{
|
||||
MOZ_ASSERT(aBlobActor);
|
||||
aBlobActor->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aStreamActor);
|
||||
MOZ_ASSERT(aStream);
|
||||
// aSerializable may be null.
|
||||
MOZ_ASSERT(aIOTarget);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
mActorTarget = do_GetCurrentThread();
|
||||
MOZ_ASSERT(mActorTarget);
|
||||
}
|
||||
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dispatch()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mIOTarget);
|
||||
|
||||
nsresult rv = mIOTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
private:
|
||||
~OpenStreamRunnable() override = default;
|
||||
|
||||
bool
|
||||
IsOnOwningThread() const
|
||||
{
|
||||
return EventTargetIsOnCurrentThread(mActorTarget);
|
||||
}
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(IsOnOwningThread());
|
||||
}
|
||||
|
||||
void
|
||||
Revoke()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
#ifdef DEBUG
|
||||
mBlobActor = nullptr;
|
||||
mStreamActor = nullptr;
|
||||
#endif
|
||||
mRevoked = true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenStream()
|
||||
{
|
||||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
MOZ_ASSERT(mStream);
|
||||
|
||||
if (!mSerializable) {
|
||||
nsCOMPtr<IPrivateRemoteInputStream> remoteStream =
|
||||
do_QueryInterface(mStream);
|
||||
MOZ_ASSERT(remoteStream, "Must QI to IPrivateRemoteInputStream here!");
|
||||
|
||||
nsCOMPtr<nsIInputStream> realStream =
|
||||
remoteStream->BlockAndGetInternalStream();
|
||||
NS_ENSURE_TRUE(realStream, NS_ERROR_FAILURE);
|
||||
|
||||
mSerializable = do_QueryInterface(realStream);
|
||||
if (!mSerializable) {
|
||||
MOZ_ASSERT(false, "Must be serializable!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mStream.swap(realStream);
|
||||
}
|
||||
|
||||
// To force the stream open we call Available(). We don't actually care
|
||||
// how much data is available.
|
||||
uint64_t available;
|
||||
if (NS_FAILED(mStream->Available(&available))) {
|
||||
NS_WARNING("Available failed on this stream!");
|
||||
}
|
||||
|
||||
if (mActorTarget) {
|
||||
nsresult rv = mActorTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CloseStream()
|
||||
{
|
||||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
MOZ_ASSERT(mStream);
|
||||
|
||||
// Going to always release here.
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
mStream.swap(stream);
|
||||
|
||||
nsCOMPtr<nsIThread> ioTarget;
|
||||
mIOTarget.swap(ioTarget);
|
||||
|
||||
DebugOnly<nsresult> rv = stream->Close();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to close stream!");
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewRunnableMethod(ioTarget, &nsIThread::Shutdown)));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SendResponse()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mStream);
|
||||
MOZ_ASSERT(mSerializable);
|
||||
MOZ_ASSERT(mIOTarget);
|
||||
MOZ_ASSERT(!mClosing);
|
||||
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable;
|
||||
mSerializable.swap(serializable);
|
||||
|
||||
if (mRevoked) {
|
||||
MOZ_ASSERT(!mBlobActor);
|
||||
MOZ_ASSERT(!mStreamActor);
|
||||
}
|
||||
else {
|
||||
MOZ_ASSERT(mBlobActor);
|
||||
MOZ_ASSERT(mBlobActor->HasManager());
|
||||
MOZ_ASSERT(mStreamActor);
|
||||
|
||||
InputStreamParams params;
|
||||
nsTArray<FileDescriptor> fds;
|
||||
serializable->Serialize(params, fds);
|
||||
|
||||
MOZ_ASSERT(params.type() != InputStreamParams::T__None);
|
||||
|
||||
OptionalFileDescriptorSet optionalFDSet;
|
||||
if (nsIContentParent* contentManager = mBlobActor->GetContentManager()) {
|
||||
ConstructFileDescriptorSet(contentManager, fds, optionalFDSet);
|
||||
} else {
|
||||
ConstructFileDescriptorSet(mBlobActor->GetBackgroundManager(),
|
||||
fds,
|
||||
optionalFDSet);
|
||||
}
|
||||
|
||||
mStreamActor->Destroy(params, optionalFDSet);
|
||||
|
||||
mBlobActor->NoteRunnableCompleted(this);
|
||||
|
||||
#ifdef DEBUG
|
||||
mBlobActor = nullptr;
|
||||
mStreamActor = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// If our luck is *really* bad then it is possible for the CloseStream() and
|
||||
// nsIThread::Shutdown() functions to run before the Dispatch() call here
|
||||
// finishes... Keep the thread alive until this method returns.
|
||||
nsCOMPtr<nsIThread> kungFuDeathGrip = mIOTarget;
|
||||
|
||||
mClosing = true;
|
||||
|
||||
nsresult rv = kungFuDeathGrip->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(mIOTarget);
|
||||
|
||||
if (IsOnOwningThread()) {
|
||||
return SendResponse();
|
||||
}
|
||||
|
||||
if (!mClosing) {
|
||||
return OpenStream();
|
||||
}
|
||||
|
||||
return CloseStream();
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(BlobParent::OpenStreamRunnable, Runnable)
|
||||
|
||||
/*******************************************************************************
|
||||
* BlobChild::RemoteBlobImpl Declaration
|
||||
******************************************************************************/
|
||||
@ -1808,7 +1460,6 @@ class BlobChild::RemoteBlobImpl
|
||||
, public nsIRemoteBlob
|
||||
{
|
||||
protected:
|
||||
class CreateStreamHelper;
|
||||
class WorkerHolder;
|
||||
|
||||
BlobChild* mActor;
|
||||
@ -1939,13 +1590,6 @@ public:
|
||||
mDifferentProcessBlobImpl = nullptr;
|
||||
}
|
||||
|
||||
// Used only by CreateStreamHelper, it dispatches a runnable to the target
|
||||
// thread. This thread can be the main-thread, the background thread or a
|
||||
// worker. If the thread is a worker, the aRunnable is wrapper into a
|
||||
// ControlRunnable in order to avoid to be blocked into a sync event loop.
|
||||
nsresult
|
||||
DispatchToTarget(nsIRunnable* aRunnable);
|
||||
|
||||
void
|
||||
WorkerHasNotified();
|
||||
|
||||
@ -1986,36 +1630,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class BlobChild::RemoteBlobImpl::CreateStreamHelper final
|
||||
: public CancelableRunnable
|
||||
{
|
||||
Monitor mMonitor;
|
||||
RefPtr<RemoteBlobImpl> mRemoteBlobImpl;
|
||||
RefPtr<RemoteInputStream> mInputStream;
|
||||
const uint64_t mStart;
|
||||
const uint64_t mLength;
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
explicit CreateStreamHelper(RemoteBlobImpl* aRemoteBlobImpl);
|
||||
|
||||
nsresult
|
||||
GetStream(nsIInputStream** aInputStream);
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
private:
|
||||
~CreateStreamHelper() override
|
||||
{
|
||||
MOZ_ASSERT(!mRemoteBlobImpl);
|
||||
MOZ_ASSERT(!mInputStream);
|
||||
MOZ_ASSERT(mDone);
|
||||
}
|
||||
|
||||
void
|
||||
RunInternal(RemoteBlobImpl* aBaseRemoteBlobImpl, bool aNotify);
|
||||
};
|
||||
|
||||
class BlobChild::RemoteBlobSliceImpl final
|
||||
: public RemoteBlobImpl
|
||||
{
|
||||
@ -2439,11 +2053,7 @@ RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CreateStreamHelper> helper = new CreateStreamHelper(this);
|
||||
aRv = helper->GetStream(aStream);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
// Broken method...
|
||||
}
|
||||
|
||||
int64_t
|
||||
@ -2541,38 +2151,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
nsresult
|
||||
BlobChild::
|
||||
RemoteBlobImpl::DispatchToTarget(nsIRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
// We have to protected mWorkerPrivate because this method can be called by
|
||||
// any thread (sort of).
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
MOZ_ASSERT(mWorkerHolder);
|
||||
|
||||
RefPtr<RemoteBlobControlRunnable> controlRunnable =
|
||||
new RemoteBlobControlRunnable(mWorkerPrivate, aRunnable);
|
||||
if (!controlRunnable->Dispatch()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = BaseRemoteBlobImpl()->GetActorEventTarget();
|
||||
if (!target) {
|
||||
target = do_GetMainThread();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
return target->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
BlobChild::
|
||||
RemoteBlobImpl::WorkerHasNotified()
|
||||
@ -2585,166 +2163,6 @@ RemoteBlobImpl::WorkerHasNotified()
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BlobChild::RemoteBlobImpl::CreateStreamHelper
|
||||
******************************************************************************/
|
||||
|
||||
BlobChild::RemoteBlobImpl::
|
||||
CreateStreamHelper::CreateStreamHelper(RemoteBlobImpl* aRemoteBlobImpl)
|
||||
: mMonitor("BlobChild::RemoteBlobImpl::CreateStreamHelper::mMonitor")
|
||||
, mRemoteBlobImpl(aRemoteBlobImpl)
|
||||
, mStart(aRemoteBlobImpl->IsSlice() ? aRemoteBlobImpl->AsSlice()->Start() : 0)
|
||||
, mLength(0)
|
||||
, mDone(false)
|
||||
{
|
||||
// This may be created on any thread.
|
||||
MOZ_ASSERT(aRemoteBlobImpl);
|
||||
|
||||
ErrorResult rv;
|
||||
const_cast<uint64_t&>(mLength) = aRemoteBlobImpl->GetSize(rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
}
|
||||
|
||||
nsresult
|
||||
BlobChild::RemoteBlobImpl::
|
||||
CreateStreamHelper::GetStream(nsIInputStream** aInputStream)
|
||||
{
|
||||
// This may be called on any thread.
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(mRemoteBlobImpl);
|
||||
MOZ_ASSERT(!mInputStream);
|
||||
MOZ_ASSERT(!mDone);
|
||||
|
||||
RefPtr<RemoteBlobImpl> baseRemoteBlobImpl =
|
||||
mRemoteBlobImpl->BaseRemoteBlobImpl();
|
||||
MOZ_ASSERT(baseRemoteBlobImpl);
|
||||
|
||||
if (EventTargetIsOnCurrentThread(baseRemoteBlobImpl->GetActorEventTarget())) {
|
||||
// RunInternal will populate mInputStream using the correct mStart/mLength
|
||||
// value.
|
||||
RunInternal(baseRemoteBlobImpl, false);
|
||||
} else if (PBackgroundChild* manager = mozilla::ipc::BackgroundChild::GetForCurrentThread()) {
|
||||
// In case we are on a PBackground thread and this is not the owning thread,
|
||||
// we need to create a new actor here. This actor must be created for the
|
||||
// baseRemoteBlobImpl, which can be the mRemoteBlobImpl or the parent one,
|
||||
// in case we are dealing with a sliced blob.
|
||||
BlobChild* blobChild = BlobChild::GetOrCreate(manager, baseRemoteBlobImpl);
|
||||
MOZ_ASSERT(blobChild);
|
||||
|
||||
// Note that baseBlobImpl is generated by the actor, and the actor is
|
||||
// created from the baseRemoteBlobImpl. This means that baseBlobImpl is the
|
||||
// remote blobImpl on PBackground of baseRemoteBlobImpl.
|
||||
RefPtr<BlobImpl> baseBlobImpl = blobChild->GetBlobImpl();
|
||||
MOZ_ASSERT(baseBlobImpl);
|
||||
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIInputStream> baseInputStream;
|
||||
baseBlobImpl->GetInternalStream(getter_AddRefs(baseInputStream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
// baseInputStream is the stream of the baseRemoteBlobImpl. If
|
||||
// mRemoteBlobImpl is a slice of baseRemoteBlobImpl, here we need to slice
|
||||
// baseInputStream.
|
||||
if (mRemoteBlobImpl->IsSlice()) {
|
||||
RefPtr<SlicedInputStream> slicedInputStream =
|
||||
new SlicedInputStream(baseInputStream, mStart, mLength);
|
||||
slicedInputStream.forget(aInputStream);
|
||||
} else {
|
||||
baseInputStream.forget(aInputStream);
|
||||
}
|
||||
|
||||
mRemoteBlobImpl = nullptr;
|
||||
mDone = true;
|
||||
return NS_OK;
|
||||
} else {
|
||||
nsresult rv = baseRemoteBlobImpl->DispatchToTarget(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DebugOnly<bool> warned = false;
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
while (!mDone) {
|
||||
#ifdef DEBUG
|
||||
if (!warned) {
|
||||
NS_WARNING("RemoteBlobImpl::GetInternalStream() called on thread "
|
||||
"that can't send messages, blocking here to wait for the "
|
||||
"actor's thread to send the message!");
|
||||
}
|
||||
#endif
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mRemoteBlobImpl);
|
||||
MOZ_ASSERT(mDone);
|
||||
|
||||
if (!mInputStream) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mInputStream.forget(aInputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BlobChild::RemoteBlobImpl::
|
||||
CreateStreamHelper::RunInternal(RemoteBlobImpl* aBaseRemoteBlobImpl,
|
||||
bool aNotify)
|
||||
{
|
||||
MOZ_ASSERT(aBaseRemoteBlobImpl);
|
||||
MOZ_ASSERT(aBaseRemoteBlobImpl->ActorEventTargetIsOnCurrentThread());
|
||||
MOZ_ASSERT(!mInputStream);
|
||||
MOZ_ASSERT(!mDone);
|
||||
|
||||
if (BlobChild* actor = aBaseRemoteBlobImpl->GetActor()) {
|
||||
RefPtr<RemoteInputStream> stream;
|
||||
|
||||
if (!NS_IsMainThread() && GetCurrentThreadWorkerPrivate()) {
|
||||
stream =
|
||||
new RemoteInputStream(actor, mRemoteBlobImpl, mStart, mLength);
|
||||
} else {
|
||||
stream = new RemoteInputStream(mRemoteBlobImpl, mStart, mLength);
|
||||
}
|
||||
|
||||
auto* streamActor = new InputStreamChild(stream);
|
||||
if (actor->SendPBlobStreamConstructor(streamActor, mStart, mLength)) {
|
||||
stream.swap(mInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
mRemoteBlobImpl = nullptr;
|
||||
|
||||
if (aNotify) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mDone = true;
|
||||
lock.Notify();
|
||||
} else {
|
||||
mDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BlobChild::RemoteBlobImpl::
|
||||
CreateStreamHelper::Run()
|
||||
{
|
||||
MOZ_ASSERT(mRemoteBlobImpl);
|
||||
MOZ_ASSERT(mRemoteBlobImpl->ActorEventTargetIsOnCurrentThread());
|
||||
|
||||
RefPtr<RemoteBlobImpl> baseRemoteBlobImpl =
|
||||
mRemoteBlobImpl->BaseRemoteBlobImpl();
|
||||
MOZ_ASSERT(baseRemoteBlobImpl);
|
||||
|
||||
RunInternal(baseRemoteBlobImpl, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BlobChild::RemoteBlobSliceImpl
|
||||
******************************************************************************/
|
||||
@ -3828,24 +3246,6 @@ BlobChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
#endif
|
||||
}
|
||||
|
||||
PBlobStreamChild*
|
||||
BlobChild::AllocPBlobStreamChild(const uint64_t& aStart,
|
||||
const uint64_t& aLength)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return new InputStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
BlobChild::DeallocPBlobStreamChild(PBlobStreamChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
delete static_cast<InputStreamChild*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BlobChild::RecvCreatedFromKnownBlob()
|
||||
{
|
||||
@ -4380,28 +3780,6 @@ BlobParent::NoteDyingRemoteBlobImpl()
|
||||
Unused << PBlobParent::Send__delete__(this);
|
||||
}
|
||||
|
||||
void
|
||||
BlobParent::NoteRunnableCompleted(OpenStreamRunnable* aRunnable)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
for (uint32_t count = mOpenStreamRunnables.Length(), index = 0;
|
||||
index < count;
|
||||
index++) {
|
||||
nsRevocableEventPtr<OpenStreamRunnable>& runnable =
|
||||
mOpenStreamRunnables[index];
|
||||
|
||||
if (runnable.get() == aRunnable) {
|
||||
runnable.Forget();
|
||||
mOpenStreamRunnables.RemoveElementAt(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CRASH("Runnable not in our array!");
|
||||
}
|
||||
|
||||
bool
|
||||
BlobParent::IsOnOwningThread() const
|
||||
{
|
||||
@ -4430,139 +3808,6 @@ BlobParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
#endif
|
||||
}
|
||||
|
||||
PBlobStreamParent*
|
||||
BlobParent::AllocPBlobStreamParent(const uint64_t& aStart,
|
||||
const uint64_t& aLength)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_WARN_IF(mRemoteBlobImpl)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new InputStreamParent();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BlobParent::RecvPBlobStreamConstructor(PBlobStreamParent* aActor,
|
||||
const uint64_t& aStart,
|
||||
const uint64_t& aLength)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(mBlobImpl);
|
||||
MOZ_ASSERT(!mRemoteBlobImpl);
|
||||
MOZ_ASSERT(mOwnsBlobImpl);
|
||||
|
||||
auto* actor = static_cast<InputStreamParent*>(aActor);
|
||||
|
||||
// Make sure we can't overflow.
|
||||
if (NS_WARN_IF(UINT64_MAX - aLength < aStart)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
ErrorResult errorResult;
|
||||
uint64_t blobLength = mBlobImpl->GetSize(errorResult);
|
||||
MOZ_ASSERT(!errorResult.Failed());
|
||||
|
||||
if (NS_WARN_IF(aStart + aLength > blobLength)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl;
|
||||
|
||||
if (!aStart && aLength == blobLength) {
|
||||
blobImpl = mBlobImpl;
|
||||
} else {
|
||||
nsString type;
|
||||
mBlobImpl->GetType(type);
|
||||
|
||||
blobImpl = mBlobImpl->CreateSlice(aStart, aLength, type, errorResult);
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
blobImpl->GetInternalStream(getter_AddRefs(stream), errorResult);
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// If the stream is entirely backed by memory then we can serialize and send
|
||||
// it immediately.
|
||||
if (mBlobImpl->IsMemoryFile()) {
|
||||
InputStreamParams params;
|
||||
nsTArray<FileDescriptor> fds;
|
||||
InputStreamHelper::SerializeInputStream(stream, params, fds);
|
||||
|
||||
MOZ_ASSERT(params.type() != InputStreamParams::T__None);
|
||||
MOZ_ASSERT(fds.IsEmpty());
|
||||
|
||||
if (!actor->Destroy(params, void_t())) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlobImpl);
|
||||
nsCOMPtr<IPrivateRemoteInputStream> remoteStream;
|
||||
if (remoteBlob) {
|
||||
remoteStream = do_QueryInterface(stream);
|
||||
}
|
||||
|
||||
// There are three cases in which we can use the stream obtained from the blob
|
||||
// directly as our serialized stream:
|
||||
//
|
||||
// 1. The blob is not a remote blob.
|
||||
// 2. The blob is a remote blob that represents this actor.
|
||||
// 3. The blob is a remote blob representing a different actor but we
|
||||
// already have a non-remote, i.e. serialized, serialized stream.
|
||||
//
|
||||
// In all other cases we need to be on a background thread before we can get
|
||||
// to the real stream.
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializableStream;
|
||||
if (!remoteBlob ||
|
||||
remoteBlob->GetBlobParent() == this ||
|
||||
!remoteStream) {
|
||||
serializableStream = do_QueryInterface(stream);
|
||||
if (!serializableStream) {
|
||||
MOZ_ASSERT(false, "Must be serializable!");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> target;
|
||||
errorResult = NS_NewNamedThread("Blob Opener", getter_AddRefs(target));
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
RefPtr<OpenStreamRunnable> runnable =
|
||||
new OpenStreamRunnable(this, actor, stream, serializableStream, target);
|
||||
|
||||
errorResult = runnable->Dispatch();
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// nsRevocableEventPtr lacks some of the operators needed for anything nicer.
|
||||
*mOpenStreamRunnables.AppendElement() = runnable;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
BlobParent::DeallocPBlobStreamParent(PBlobStreamParent* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
delete static_cast<InputStreamParent*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams)
|
||||
{
|
||||
@ -4621,44 +3866,6 @@ BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams)
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BlobParent::RecvBlobStreamSync(const uint64_t& aStart,
|
||||
const uint64_t& aLength,
|
||||
InputStreamParams* aParams,
|
||||
OptionalFileDescriptorSet* aFDs)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mBlobImpl);
|
||||
MOZ_ASSERT(!mRemoteBlobImpl);
|
||||
MOZ_ASSERT(mOwnsBlobImpl);
|
||||
|
||||
bool finished = false;
|
||||
|
||||
{
|
||||
// Calling RecvPBlobStreamConstructor() may synchronously delete the actor
|
||||
// we pass in so don't touch it outside this block.
|
||||
auto* streamActor = new InputStreamParent(&finished, aParams, aFDs);
|
||||
|
||||
if (NS_WARN_IF(!RecvPBlobStreamConstructor(streamActor, aStart, aLength))) {
|
||||
// If RecvPBlobStreamConstructor() returns false then it is our
|
||||
// responsibility to destroy the actor.
|
||||
delete streamActor;
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (finished) {
|
||||
// The actor is already dead and we have already set our out params.
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// The actor is alive and will be doing asynchronous work to load the stream.
|
||||
// Spin a nested loop here while we wait for it.
|
||||
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return finished; }));
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BlobParent::RecvWaitForSliceCreation()
|
||||
{
|
||||
@ -4813,30 +4020,5 @@ IDTableEntry::GetOrCreateInternal(const nsID& aID,
|
||||
return entry.forget();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Other stuff
|
||||
******************************************************************************/
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
InputStreamChild::Recv__delete__(const InputStreamParams& aParams,
|
||||
const OptionalFileDescriptorSet& aOptionalSet)
|
||||
{
|
||||
MOZ_ASSERT(mRemoteStream);
|
||||
mRemoteStream->AssertIsOnOwningThread();
|
||||
|
||||
nsTArray<FileDescriptor> fds;
|
||||
OptionalFileDescriptorSetToFDs(
|
||||
// XXX Fix this somehow...
|
||||
const_cast<OptionalFileDescriptorSet&>(aOptionalSet),
|
||||
fds);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream =
|
||||
InputStreamHelper::DeserializeInputStream(aParams, fds);
|
||||
MOZ_ASSERT(stream);
|
||||
|
||||
mRemoteStream->SetStream(stream);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -29,7 +29,6 @@ class Blob;
|
||||
class BlobImpl;
|
||||
class ContentChild;
|
||||
class nsIContentChild;
|
||||
class PBlobStreamChild;
|
||||
|
||||
class BlobChild final
|
||||
: public PBlobChild
|
||||
@ -211,13 +210,6 @@ private:
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual PBlobStreamChild*
|
||||
AllocPBlobStreamChild(const uint64_t& aStart,
|
||||
const uint64_t& aLength) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBlobStreamChild(PBlobStreamChild* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvCreatedFromKnownBlob() override;
|
||||
};
|
||||
|
@ -35,7 +35,6 @@ namespace dom {
|
||||
class ContentParent;
|
||||
class BlobImpl;
|
||||
class nsIContentParent;
|
||||
class PBlobStreamParent;
|
||||
|
||||
class BlobParent final
|
||||
: public PBlobParent
|
||||
@ -45,9 +44,6 @@ class BlobParent final
|
||||
class IDTableEntry;
|
||||
typedef nsDataHashtable<nsIDHashKey, IDTableEntry*> IDTable;
|
||||
|
||||
class OpenStreamRunnable;
|
||||
friend class OpenStreamRunnable;
|
||||
|
||||
class RemoteBlobImpl;
|
||||
|
||||
struct CreateBlobImplMetadata;
|
||||
@ -64,15 +60,6 @@ class BlobParent final
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
|
||||
// nsIInputStreams backed by files must ensure that the files are actually
|
||||
// opened and closed on a background thread before we can send their file
|
||||
// handles across to the child. The child process could crash during this
|
||||
// process so we need to make sure we cancel the intended response in such a
|
||||
// case. We do that by holding an array of nsRevocableEventPtr. If the child
|
||||
// crashes then this actor will be destroyed and the nsRevocableEventPtr
|
||||
// destructor will cancel any stream events that are currently in flight.
|
||||
nsTArray<nsRevocableEventPtr<OpenStreamRunnable>> mOpenStreamRunnables;
|
||||
|
||||
RefPtr<IDTableEntry> mIDTableEntry;
|
||||
|
||||
bool mOwnsBlobImpl;
|
||||
@ -189,9 +176,6 @@ private:
|
||||
void
|
||||
NoteDyingRemoteBlobImpl();
|
||||
|
||||
void
|
||||
NoteRunnableCompleted(OpenStreamRunnable* aRunnable);
|
||||
|
||||
nsIEventTarget*
|
||||
EventTarget() const
|
||||
{
|
||||
@ -205,27 +189,9 @@ private:
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual PBlobStreamParent*
|
||||
AllocPBlobStreamParent(const uint64_t& aStart,
|
||||
const uint64_t& aLength) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPBlobStreamConstructor(PBlobStreamParent* aActor,
|
||||
const uint64_t& aStart,
|
||||
const uint64_t& aLength) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBlobStreamParent(PBlobStreamParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvResolveMystery(const ResolveMysteryParams& aParams) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvBlobStreamSync(const uint64_t& aStart,
|
||||
const uint64_t& aLength,
|
||||
InputStreamParams* aParams,
|
||||
OptionalFileDescriptorSet* aFDs) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvWaitForSliceCreation() override;
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PBlobStream;
|
||||
include protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
include protocol PFileDescriptorSet;
|
||||
@ -26,19 +25,13 @@ union ResolveMysteryParams
|
||||
sync protocol PBlob
|
||||
{
|
||||
manager PBackground or PContent or PContentBridge;
|
||||
manages PBlobStream;
|
||||
|
||||
both:
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async PBlobStream(uint64_t begin, uint64_t length);
|
||||
|
||||
async ResolveMystery(ResolveMysteryParams params);
|
||||
|
||||
sync BlobStreamSync(uint64_t begin, uint64_t length)
|
||||
returns (InputStreamParams params, OptionalFileDescriptorSet fds);
|
||||
|
||||
sync WaitForSliceCreation();
|
||||
|
||||
// Use only for testing!
|
||||
|
@ -1,22 +0,0 @@
|
||||
/* 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 protocol PBlob;
|
||||
include protocol PFileDescriptorSet;
|
||||
include BlobTypes;
|
||||
include InputStreamParams;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
protocol PBlobStream
|
||||
{
|
||||
manager PBlob;
|
||||
|
||||
child:
|
||||
async __delete__(InputStreamParams params, OptionalFileDescriptorSet fds);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -35,7 +35,6 @@ IPDL_SOURCES += [
|
||||
'BlobTypes.ipdlh',
|
||||
'IPCBlob.ipdlh',
|
||||
'PBlob.ipdl',
|
||||
'PBlobStream.ipdl',
|
||||
'PIPCBlobInputStream.ipdl',
|
||||
'PPendingIPCBlob.ipdl',
|
||||
]
|
||||
|
@ -807,8 +807,6 @@ description =
|
||||
# The rest
|
||||
[PHeapSnapshotTempFileHelper::OpenHeapSnapshotTempFile]
|
||||
description =
|
||||
[PBlob::BlobStreamSync]
|
||||
description =
|
||||
[PBlob::WaitForSliceCreation]
|
||||
description =
|
||||
[PBlob::GetFileId]
|
||||
|
Loading…
Reference in New Issue
Block a user