зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1371699 - Implement NonBlockingAsyncInputStream - nsIAsyncInputStream wrapper for non-blocking non-async streams, r=froydnj
This commit is contained in:
Родитель
806d5dbc75
Коммит
890628437c
|
@ -0,0 +1,300 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "NonBlockingAsyncInputStream.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace {
|
||||
|
||||
class AsyncWaitRunnable final : public CancelableRunnable
|
||||
{
|
||||
RefPtr<NonBlockingAsyncInputStream> mStream;
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
|
||||
public:
|
||||
AsyncWaitRunnable(NonBlockingAsyncInputStream* aStream,
|
||||
nsIInputStreamCallback* aCallback)
|
||||
: CancelableRunnable("AsyncWaitRunnable")
|
||||
, mStream(aStream)
|
||||
, mCallback(aCallback)
|
||||
{}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
mCallback->OnInputStreamReady(mStream);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
NS_IMPL_ADDREF(NonBlockingAsyncInputStream);
|
||||
NS_IMPL_RELEASE(NonBlockingAsyncInputStream);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(NonBlockingAsyncInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
|
||||
mWeakCloneableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
|
||||
mWeakIPCSerializableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream,
|
||||
mWeakSeekableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
/* static */ nsresult
|
||||
NonBlockingAsyncInputStream::Create(nsIInputStream* aInputStream,
|
||||
nsIAsyncInputStream** aResult)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aResult);
|
||||
|
||||
bool nonBlocking = false;
|
||||
nsresult rv = aInputStream->IsNonBlocking(&nonBlocking);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(nonBlocking);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
|
||||
do_QueryInterface(aInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(!asyncInputStream);
|
||||
|
||||
RefPtr<NonBlockingAsyncInputStream> stream =
|
||||
new NonBlockingAsyncInputStream(aInputStream);
|
||||
|
||||
stream.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NonBlockingAsyncInputStream::NonBlockingAsyncInputStream(nsIInputStream* aInputStream)
|
||||
: mInputStream(aInputStream)
|
||||
, mWeakCloneableInputStream(nullptr)
|
||||
, mWeakIPCSerializableInputStream(nullptr)
|
||||
, mWeakSeekableInputStream(nullptr)
|
||||
, mClosed(false)
|
||||
{
|
||||
MOZ_ASSERT(mInputStream);
|
||||
|
||||
nsCOMPtr<nsICloneableInputStream> cloneableStream =
|
||||
do_QueryInterface(aInputStream);
|
||||
if (cloneableStream && SameCOMIdentity(aInputStream, cloneableStream)) {
|
||||
mWeakCloneableInputStream = cloneableStream;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
|
||||
do_QueryInterface(aInputStream);
|
||||
if (serializableStream &&
|
||||
SameCOMIdentity(aInputStream, serializableStream)) {
|
||||
mWeakIPCSerializableInputStream = serializableStream;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISeekableStream> seekableStream =
|
||||
do_QueryInterface(aInputStream);
|
||||
if (seekableStream && SameCOMIdentity(aInputStream, seekableStream)) {
|
||||
mWeakSeekableInputStream = seekableStream;
|
||||
}
|
||||
}
|
||||
|
||||
NonBlockingAsyncInputStream::~NonBlockingAsyncInputStream()
|
||||
{}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::Close()
|
||||
{
|
||||
if (mClosed) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
|
||||
NS_ENSURE_STATE(mInputStream);
|
||||
nsresult rv = mInputStream->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mWaitClosureOnly.reset();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If we have a WaitClosureOnly runnable, it's time to use it.
|
||||
if (mWaitClosureOnly.isSome()) {
|
||||
nsCOMPtr<nsIRunnable> waitClosureOnlyRunnable =
|
||||
Move(mWaitClosureOnly->mRunnable);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> waitClosureOnlyEventTarget =
|
||||
Move(mWaitClosureOnly->mEventTarget);
|
||||
|
||||
mWaitClosureOnly.reset();
|
||||
|
||||
if (waitClosureOnlyEventTarget) {
|
||||
waitClosureOnlyEventTarget->Dispatch(waitClosureOnlyRunnable,
|
||||
NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
waitClosureOnlyRunnable->Run();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIInputStream interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::Available(uint64_t* aLength)
|
||||
{
|
||||
return mInputStream->Available(aLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::Read(char* aBuffer, uint32_t aCount,
|
||||
uint32_t* aReadCount)
|
||||
{
|
||||
return mInputStream->Read(aBuffer, aCount, aReadCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void* aClosure, uint32_t aCount,
|
||||
uint32_t *aResult)
|
||||
{
|
||||
return mInputStream->ReadSegments(aWriter, aClosure, aCount, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::IsNonBlocking(bool* aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsICloneableInputStream interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::GetCloneable(bool* aCloneable)
|
||||
{
|
||||
NS_ENSURE_STATE(mWeakCloneableInputStream);
|
||||
return mWeakCloneableInputStream->GetCloneable(aCloneable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::Clone(nsIInputStream** aResult)
|
||||
{
|
||||
NS_ENSURE_STATE(mWeakCloneableInputStream);
|
||||
|
||||
nsCOMPtr<nsIInputStream> clonedStream;
|
||||
nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream;
|
||||
rv = Create(clonedStream, getter_AddRefs(asyncStream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
asyncStream.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIAsyncInputStream interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::CloseWithStatus(nsresult aStatus)
|
||||
{
|
||||
return Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
uint32_t aFlags,
|
||||
uint32_t aRequestedCount,
|
||||
nsIEventTarget* aEventTarget)
|
||||
{
|
||||
if (aCallback && mWaitClosureOnly.isSome()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!aCallback) {
|
||||
// Canceling previous callback.
|
||||
mWaitClosureOnly.reset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<NonBlockingAsyncInputStream> self = this;
|
||||
nsCOMPtr<nsIInputStreamCallback> callback = aCallback;
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new AsyncWaitRunnable(this, aCallback);
|
||||
if ((aFlags & nsIAsyncInputStream::WAIT_CLOSURE_ONLY) && !mClosed) {
|
||||
mWaitClosureOnly.emplace(runnable, aEventTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aEventTarget) {
|
||||
return aEventTarget->Dispatch(runnable.forget());
|
||||
}
|
||||
|
||||
return runnable->Run();
|
||||
}
|
||||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void
|
||||
NonBlockingAsyncInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors)
|
||||
{
|
||||
MOZ_ASSERT(mWeakIPCSerializableInputStream);
|
||||
InputStreamHelper::SerializeInputStream(mInputStream, aParams,
|
||||
aFileDescriptors);
|
||||
}
|
||||
|
||||
bool
|
||||
NonBlockingAsyncInputStream::Deserialize(const mozilla::ipc::InputStreamParams& aParams,
|
||||
const FileDescriptorArray& aFileDescriptors)
|
||||
{
|
||||
MOZ_CRASH("NonBlockingAsyncInputStream cannot be deserialized!");
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<uint64_t>
|
||||
NonBlockingAsyncInputStream::ExpectedSerializedLength()
|
||||
{
|
||||
NS_ENSURE_TRUE(mWeakIPCSerializableInputStream, Nothing());
|
||||
return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
|
||||
}
|
||||
|
||||
// nsISeekableStream
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
NS_ENSURE_STATE(mWeakSeekableInputStream);
|
||||
return mWeakSeekableInputStream->Seek(aWhence, aOffset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::Tell(int64_t *aResult)
|
||||
{
|
||||
NS_ENSURE_STATE(mWeakSeekableInputStream);
|
||||
return mWeakSeekableInputStream->Tell(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NonBlockingAsyncInputStream::SetEOF()
|
||||
{
|
||||
NS_ENSURE_STATE(mWeakSeekableInputStream);
|
||||
mClosed = true;
|
||||
return mWeakSeekableInputStream->SetEOF();
|
||||
}
|
||||
|
||||
} // mozilla namespace
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef NonBlockingAsyncInputStream_h
|
||||
#define NonBlockingAsyncInputStream_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsICloneableInputStream.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
||||
// This class aims to wrap a non-blocking and non-async inputStream and expose
|
||||
// it as nsIAsyncInputStream.
|
||||
// Probably you don't want to use this class directly. Instead use
|
||||
// NS_MakeAsyncNonBlockingInputStream() as it will handle different stream
|
||||
// variants without requiring you to special-case them yourself.
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class NonBlockingAsyncInputStream final : public nsIAsyncInputStream
|
||||
, public nsICloneableInputStream
|
||||
, public nsIIPCSerializableInputStream
|
||||
, public nsISeekableStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
NS_DECL_NSICLONEABLEINPUTSTREAM
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
|
||||
// |aInputStream| must be a non-blocking, non-async inputSteam.
|
||||
static nsresult
|
||||
Create(nsIInputStream* aInputStream,
|
||||
nsIAsyncInputStream** aAsyncInputStream);
|
||||
|
||||
private:
|
||||
explicit NonBlockingAsyncInputStream(nsIInputStream* aInputStream);
|
||||
~NonBlockingAsyncInputStream();
|
||||
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
|
||||
// Raw pointers because these are just QI of mInputStream.
|
||||
nsICloneableInputStream* MOZ_NON_OWNING_REF mWeakCloneableInputStream;
|
||||
nsIIPCSerializableInputStream* MOZ_NON_OWNING_REF mWeakIPCSerializableInputStream;
|
||||
nsISeekableStream* MOZ_NON_OWNING_REF mWeakSeekableInputStream;
|
||||
|
||||
struct WaitClosureOnly
|
||||
{
|
||||
WaitClosureOnly(nsIRunnable* aRunnable, nsIEventTarget* aEventTarget)
|
||||
: mRunnable(aRunnable)
|
||||
, mEventTarget(aEventTarget)
|
||||
{}
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
};
|
||||
|
||||
// This is set when AsyncWait is called with a callback and with
|
||||
// WAIT_CLOSURE_ONLY as flag.
|
||||
Maybe<WaitClosureOnly> mWaitClosureOnly;
|
||||
|
||||
bool mClosed;
|
||||
};
|
||||
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // NonBlockingAsyncInputStream_h
|
|
@ -83,6 +83,7 @@ EXPORTS += [
|
|||
|
||||
EXPORTS.mozilla += [
|
||||
'Base64.h',
|
||||
'NonBlockingAsyncInputStream.h',
|
||||
'SlicedInputStream.h',
|
||||
'SnappyCompressOutputStream.h',
|
||||
'SnappyFrameUtils.h',
|
||||
|
@ -93,6 +94,7 @@ UNIFIED_SOURCES += [
|
|||
'Base64.cpp',
|
||||
'crc32c.c',
|
||||
'FileDescriptorFile.cpp',
|
||||
'NonBlockingAsyncInputStream.cpp',
|
||||
'nsAnonymousTemporaryFile.cpp',
|
||||
'nsAppFileLocationProvider.cpp',
|
||||
'nsBinaryStream.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче