Bug 1359359 - FileReaderSync should support nsIAsyncInputStream, r=smaug

This commit is contained in:
Andrea Marchesini 2017-04-25 22:23:46 +02:00
Родитель 0aedf284ff
Коммит b6565e5cf3
2 изменённых файлов: 128 добавлений и 3 удалений

Просмотреть файл

@ -25,6 +25,9 @@
#include "nsISupportsImpl.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsIAsyncInputStream.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "RuntimeService.h"
@ -75,7 +78,7 @@ FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
}
uint32_t numRead;
aRv = stream->Read(bufferData.get(), blobSize, &numRead);
aRv = Read(stream, bufferData.get(), blobSize, &numRead);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -107,7 +110,7 @@ FileReaderSync::ReadAsBinaryString(Blob& aBlob,
uint32_t numRead;
do {
char readBuf[4096];
aRv = stream->Read(readBuf, sizeof(readBuf), &numRead);
aRv = Read(stream, readBuf, sizeof(readBuf), &numRead);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -142,7 +145,7 @@ FileReaderSync::ReadAsText(Blob& aBlob,
}
uint32_t numRead = 0;
aRv = stream->Read(sniffBuf.BeginWriting(), sniffBuf.Length(), &numRead);
aRv = Read(stream, sniffBuf.BeginWriting(), sniffBuf.Length(), &numRead);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -288,3 +291,122 @@ FileReaderSync::ConvertStream(nsIInputStream *aStream,
return rv;
}
namespace {
// This runnable is used to terminate the sync event loop.
class ReadReadyRunnable final : public WorkerSyncRunnable
{
public:
ReadReadyRunnable(WorkerPrivate* aWorkerPrivate,
nsIEventTarget* aSyncLoopTarget)
: WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget)
{}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(mSyncLoopTarget);
nsCOMPtr<nsIEventTarget> syncLoopTarget;
mSyncLoopTarget.swap(syncLoopTarget);
aWorkerPrivate->StopSyncLoop(syncLoopTarget, true);
return true;
}
private:
~ReadReadyRunnable()
{}
};
// This class implements nsIInputStreamCallback and it will be called when the
// stream is ready to be read.
class ReadCallback final : public nsIInputStreamCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
ReadCallback(WorkerPrivate* aWorkerPrivate, nsIEventTarget* aEventTarget)
: mWorkerPrivate(aWorkerPrivate)
, mEventTarget(aEventTarget)
{}
NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream* aStream) override
{
// I/O Thread. Now we need to block the sync event loop.
RefPtr<ReadReadyRunnable> runnable =
new ReadReadyRunnable(mWorkerPrivate, mEventTarget);
return mEventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
}
private:
~ReadCallback()
{}
// The worker is kept alive because of the sync event loop.
WorkerPrivate* mWorkerPrivate;
nsCOMPtr<nsIEventTarget> mEventTarget;
};
NS_IMPL_ADDREF(ReadCallback);
NS_IMPL_RELEASE(ReadCallback);
NS_INTERFACE_MAP_BEGIN(ReadCallback)
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback)
NS_INTERFACE_MAP_END
} // anonymous
nsresult
FileReaderSync::Read(nsIInputStream* aStream, char* aBuffer, uint32_t aBufferSize,
uint32_t* aRead)
{
MOZ_ASSERT(aStream);
MOZ_ASSERT(aBuffer);
MOZ_ASSERT(aRead);
// Let's try to read, directly.
nsresult rv = aStream->Read(aBuffer, aBufferSize, aRead);
if (NS_SUCCEEDED(rv) || rv != NS_BASE_STREAM_WOULD_BLOCK) {
return rv;
}
// We need to proceed async.
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
if (!asyncStream) {
return rv;
}
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
AutoSyncLoopHolder syncLoop(workerPrivate, Closing);
nsCOMPtr<nsIEventTarget> syncLoopTarget = syncLoop.GetEventTarget();
if (!syncLoopTarget) {
// SyncLoop creation can fail if the worker is shutting down.
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
RefPtr<ReadCallback> callback =
new ReadCallback(workerPrivate, syncLoopTarget);
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
rv = asyncStream->AsyncWait(callback, 0, aBufferSize, target);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!syncLoop.Run()) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
// Now, we can try to read again.
return Read(aStream, aBuffer, aBufferSize, aRead);
}

Просмотреть файл

@ -32,6 +32,9 @@ private:
nsresult ConvertStream(nsIInputStream *aStream, const char *aCharset,
nsAString &aResult);
nsresult Read(nsIInputStream* aStream, char* aBuffer, uint32_t aBufferSize,
uint32_t* aRead);
public:
static already_AddRefed<FileReaderSync>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);