Bug 1294450 - Make AutoIPCStream favour PSendStream for large input streams. r=nfroydj

This commit is contained in:
Josh Matthews 2016-09-29 06:20:00 +02:00
parent c35a0bf546
commit ee8da66177
11 changed files with 164 additions and 3 deletions

View File

@ -282,6 +282,18 @@ StreamWrapper::Deserialize(const InputStreamParams& aParams,
return false;
}
Maybe<uint64_t>
StreamWrapper::ExpectedSerializedLength()
{
nsCOMPtr<nsIIPCSerializableInputStream> stream =
do_QueryInterface(mInputStream);
if (stream) {
return stream->ExpectedSerializedLength();
}
return Nothing();
}
NS_IMPL_ISUPPORTS_INHERITED0(StreamWrapper::CloseRunnable,
Runnable)

View File

@ -1307,6 +1307,12 @@ RemoteInputStream::Deserialize(const InputStreamParams& /* aParams */,
MOZ_CRASH("RemoteInputStream should never be deserialized");
}
Maybe<uint64_t>
RemoteInputStream::ExpectedSerializedLength()
{
return Nothing();
}
nsIInputStream*
RemoteInputStream::BlockAndGetInternalStream()
{

View File

@ -20,6 +20,9 @@
#include "mozilla/ipc/SendStream.h"
#include "mozilla/Unused.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIPipe.h"
#include "nsStreamUtils.h"
namespace mozilla {
namespace ipc {
@ -122,17 +125,41 @@ SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager)
MOZ_ASSERT(aStream);
MOZ_ASSERT(aManager);
// If a stream is known to be larger than 1MB, prefer sending it in chunks.
const uint64_t kTooLargeStream = 1024 * 1024;
// First attempt simple stream serialization
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
do_QueryInterface(aStream);
if (serializable) {
uint64_t expectedLength =
serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
if (serializable && expectedLength < kTooLargeStream) {
SerializeInputStreamWithFdsChild(aStream, aValue, aManager);
return;
}
// As a fallback, attempt to stream the data across using a SendStream
// actor. This will fail for blocking streams.
// actor. For blocking streams, create a nonblocking pipe instead,
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
if (!asyncStream) {
const uint32_t kBufferSize = 32768; // matches SendStream buffer size.
nsCOMPtr<nsIAsyncOutputStream> sink;
DebugOnly<nsresult> rv = NS_NewPipe2(getter_AddRefs(asyncStream),
getter_AddRefs(sink),
true,
false,
kBufferSize,
UINT32_MAX);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS, kBufferSize);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
MOZ_ASSERT(asyncStream);
aValue = SendStreamChild::Create(asyncStream, aManager);
if (!aValue.get_PSendStreamChild()) {

View File

@ -8,6 +8,7 @@
#define mozilla_ipc_nsIIPCSerializableInputStream_h
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "nsISupports.h"
#include "nsTArrayForwardDeclare.h"
@ -38,6 +39,17 @@ public:
virtual bool
Deserialize(const mozilla::ipc::InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) = 0;
// The number of bytes that are expected to be written when this
// stream is serialized. A value of Some(N) indicates that N bytes
// will be written to the IPC buffer, and will be used to decide
// upon an optimal transmission mechanism. A value of Nothing
// indicates that either serializing this stream will not require
// serializing its contents (eg. a file-backed stream, or a stream
// backed by an IPC actor), or the length of the stream's contents
// cannot be determined.
virtual mozilla::Maybe<uint64_t>
ExpectedSerializedLength() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
@ -50,7 +62,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
\
virtual bool \
Deserialize(const mozilla::ipc::InputStreamParams&, \
const FileDescriptorArray&) override;
const FileDescriptorArray&) override; \
\
virtual mozilla::Maybe<uint64_t> \
ExpectedSerializedLength() override;
#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
virtual void \
@ -65,6 +80,12 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
const FileDescriptorArray& aFileDescriptors) override \
{ \
return _to Deserialize(aParams, aFileDescriptors); \
} \
\
virtual mozilla::Maybe<uint64_t> \
ExpectedSerializedLength() override \
{ \
return _to ExpectedSerializedLength(); \
}
#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
@ -82,6 +103,12 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
const FileDescriptorArray& aFileDescriptors) override \
{ \
return _to ? _to->Deserialize(aParams, aFileDescriptors) : false; \
} \
\
virtual mozilla::Maybe<uint64_t> \
ExpectedSerializedLength() override \
{ \
return _to ? _to->ExpectedSerializedLength() : Nothing(); \
}
#endif // mozilla_ipc_nsIIPCSerializableInputStream_h

View File

@ -38,6 +38,9 @@ static struct {
#endif
using namespace mozilla::ipc;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::Some;
////////////////////////////////////////////////////////////////////////////////
// nsBufferedStream
@ -541,6 +544,16 @@ nsBufferedInputStream::Deserialize(const InputStreamParams& aParams,
return true;
}
Maybe<uint64_t>
nsBufferedInputStream::ExpectedSerializedLength()
{
nsCOMPtr<nsIIPCSerializableInputStream> stream = do_QueryInterface(mStream);
if (stream) {
return stream->ExpectedSerializedLength();
}
return Nothing();
}
////////////////////////////////////////////////////////////////////////////////
// nsBufferedOutputStream

View File

@ -32,6 +32,9 @@ typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
using namespace mozilla::ipc;
using mozilla::DebugOnly;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::Some;
////////////////////////////////////////////////////////////////////////////////
// nsFileStreamBase
@ -662,6 +665,12 @@ nsFileInputStream::Deserialize(const InputStreamParams& aParams,
return true;
}
Maybe<uint64_t>
nsFileInputStream::ExpectedSerializedLength()
{
return Nothing();
}
////////////////////////////////////////////////////////////////////////////////
// nsPartialFileInputStream
@ -860,6 +869,13 @@ nsPartialFileInputStream::Deserialize(
return NS_SUCCEEDED(nsFileInputStream::Seek(NS_SEEK_SET, mStart));
}
Maybe<uint64_t>
nsPartialFileInputStream::ExpectedSerializedLength()
{
return Some(mLength);
}
nsresult
nsPartialFileInputStream::DoPendingSeek()
{

View File

@ -23,6 +23,7 @@
#include "mozilla/ipc/InputStreamUtils.h"
using namespace mozilla::ipc;
using mozilla::Maybe;
class nsMIMEInputStream : public nsIMIMEInputStream,
public nsISeekableStream,
@ -379,3 +380,11 @@ nsMIMEInputStream::Deserialize(const InputStreamParams& aParams,
return true;
}
Maybe<uint64_t>
nsMIMEInputStream::ExpectedSerializedLength()
{
nsCOMPtr<nsIIPCSerializableInputStream> serializable = do_QueryInterface(mStream);
return serializable ? serializable->ExpectedSerializedLength() : Nothing();
}

View File

@ -239,3 +239,9 @@ nsTemporaryFileInputStream::Deserialize(const InputStreamParams& aParams,
mEndPos = params.endPos();
return true;
}
Maybe<uint64_t>
nsTemporaryFileInputStream::ExpectedSerializedLength()
{
return Nothing();
}

View File

@ -29,6 +29,9 @@ using namespace mozilla;
using namespace mozilla::ipc;
using mozilla::DeprecatedAbs;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::Some;
class nsMultiplexInputStream final
: public nsIMultiplexInputStream
@ -747,6 +750,29 @@ nsMultiplexInputStream::Deserialize(const InputStreamParams& aParams,
return true;
}
Maybe<uint64_t>
nsMultiplexInputStream::ExpectedSerializedLength()
{
MutexAutoLock lock(mLock);
bool lengthValueExists = false;
uint64_t expectedLength = 0;
uint32_t streamCount = mStreams.Length();
for (uint32_t index = 0; index < streamCount; index++) {
nsCOMPtr<nsIIPCSerializableInputStream> stream = do_QueryInterface(mStreams[index]);
if (!stream) {
continue;
}
Maybe<uint64_t> length = stream->ExpectedSerializedLength();
if (length.isNothing()) {
continue;
}
lengthValueExists = true;
expectedLength += length.value();
}
return lengthValueExists ? Some(expectedLength) : Nothing();
}
NS_IMETHODIMP
nsMultiplexInputStream::GetCloneable(bool* aCloneable)
{

View File

@ -29,6 +29,8 @@
using mozilla::ipc::InputStreamParams;
using mozilla::ipc::StringInputStreamParams;
using mozilla::Maybe;
using mozilla::Some;
//
// Log module for StorageStream logging...
@ -598,6 +600,15 @@ nsStorageInputStream::Serialize(InputStreamParams& aParams, FileDescriptorArray&
aParams = params;
}
Maybe<uint64_t>
nsStorageInputStream::ExpectedSerializedLength()
{
uint64_t remaining = 0;
DebugOnly<nsresult> rv = Available(&remaining);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return Some(remaining);
}
bool
nsStorageInputStream::Deserialize(const InputStreamParams& aParams,
const FileDescriptorArray&)

View File

@ -25,6 +25,8 @@
#include "nsIIPCSerializableInputStream.h"
using namespace mozilla::ipc;
using mozilla::Maybe;
using mozilla::Some;
//-----------------------------------------------------------------------------
// nsIStringInputStream implementation
@ -354,6 +356,12 @@ nsStringInputStream::Deserialize(const InputStreamParams& aParams,
return true;
}
Maybe<uint64_t>
nsStringInputStream::ExpectedSerializedLength()
{
return Some(static_cast<uint64_t>(Length()));
}
/////////
// nsICloneableInputStream implementation
/////////