зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1359359
- FileReaderSync should support nsIAsyncInputStream, r=smaug
This commit is contained in:
Родитель
0aedf284ff
Коммит
b6565e5cf3
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче