mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 13:57:32 +00:00
Bug 1143223 Teach Cache ReadStream not to AddRef() itself in its destructor. r=ehsan
This commit is contained in:
parent
5da1c39c61
commit
63da054263
126
dom/cache/CacheStreamControlChild.cpp
vendored
126
dom/cache/CacheStreamControlChild.cpp
vendored
@ -9,13 +9,22 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetChild.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::FileDescriptorSetChild;
|
||||
using mozilla::ipc::OptionalFileDescriptorSet;
|
||||
using mozilla::ipc::PFileDescriptorSetChild;
|
||||
|
||||
// declared in ActorUtils.h
|
||||
PCacheStreamControlChild*
|
||||
AllocPCacheStreamControlChild()
|
||||
@ -42,30 +51,6 @@ CacheStreamControlChild::~CacheStreamControlChild()
|
||||
MOZ_COUNT_DTOR(cache::CacheStreamControlChild);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::AddListener(ReadStream* aListener)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ASSERT(!mListeners.Contains(aListener));
|
||||
mListeners.AppendElement(aListener);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::RemoveListener(ReadStream* aListener)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ALWAYS_TRUE(mListeners.RemoveElement(aListener));
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::NoteClosed(const nsID& aId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
unused << SendNoteClosed(aId);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::StartDestroy()
|
||||
{
|
||||
@ -83,19 +68,73 @@ CacheStreamControlChild::StartDestroy()
|
||||
RecvCloseAll();
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::SerializeControl(PCacheReadStream* aReadStreamOut)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
aReadStreamOut->controlParent() = nullptr;
|
||||
aReadStreamOut->controlChild() = this;
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<FileDescriptor>& aFds)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
PFileDescriptorSetChild* fdSet = nullptr;
|
||||
if (!aFds.IsEmpty()) {
|
||||
fdSet = Manager()->SendPFileDescriptorSetConstructor(aFds[0]);
|
||||
for (uint32_t i = 1; i < aFds.Length(); ++i) {
|
||||
unused << fdSet->SendAddFileDescriptor(aFds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fdSet) {
|
||||
aReadStreamOut->fds() = fdSet;
|
||||
} else {
|
||||
aReadStreamOut->fds() = void_t();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
nsTArray<FileDescriptor>& aFdsOut)
|
||||
{
|
||||
if (aReadStream.fds().type() !=
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto fdSetActor = static_cast<FileDescriptorSetChild*>(
|
||||
aReadStream.fds().get_PFileDescriptorSetChild());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(aFdsOut);
|
||||
MOZ_ASSERT(!aFdsOut.IsEmpty());
|
||||
|
||||
unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::NoteClosedAfterForget(const nsID& aId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
unused << SendNoteClosed(aId);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
CacheStreamControlChild::AssertOwningThread()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
CacheStreamControlChild::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
// Note, we cannot trigger IPC traffic here. So use
|
||||
// CloseStreamWithoutReporting().
|
||||
ReadStreamList::ForwardIterator iter(mListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream> stream = iter.GetNext();
|
||||
stream->CloseStreamWithoutReporting();
|
||||
}
|
||||
mListeners.Clear();
|
||||
|
||||
CloseAllReadStreamsWithoutReporting();
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
@ -103,20 +142,7 @@ bool
|
||||
CacheStreamControlChild::RecvClose(const nsID& aId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
DebugOnly<uint32_t> closedCount = 0;
|
||||
|
||||
ReadStreamList::ForwardIterator iter(mListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream> stream = iter.GetNext();
|
||||
// note, multiple streams may exist for same ID
|
||||
if (stream->MatchId(aId)) {
|
||||
stream->CloseStream();
|
||||
closedCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(closedCount > 0);
|
||||
|
||||
CloseReadStreams(aId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -124,11 +150,7 @@ bool
|
||||
CacheStreamControlChild::RecvCloseAll()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
ReadStreamList::ForwardIterator iter(mListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream> stream = iter.GetNext();
|
||||
stream->CloseStream();
|
||||
}
|
||||
CloseAllReadStreams();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
30
dom/cache/CacheStreamControlChild.h
vendored
30
dom/cache/CacheStreamControlChild.h
vendored
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/dom/cache/ActorChild.h"
|
||||
#include "mozilla/dom/cache/PCacheStreamControlChild.h"
|
||||
#include "mozilla/dom/cache/StreamControl.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -18,29 +19,42 @@ namespace cache {
|
||||
class ReadStream;
|
||||
|
||||
class CacheStreamControlChild MOZ_FINAL : public PCacheStreamControlChild
|
||||
, public StreamControl
|
||||
, public ActorChild
|
||||
{
|
||||
public:
|
||||
CacheStreamControlChild();
|
||||
~CacheStreamControlChild();
|
||||
|
||||
void AddListener(ReadStream* aListener);
|
||||
void RemoveListener(ReadStream* aListener);
|
||||
|
||||
void NoteClosed(const nsID& aId);
|
||||
|
||||
// ActorChild methods
|
||||
virtual void StartDestroy() MOZ_OVERRIDE;
|
||||
|
||||
// StreamControl methods
|
||||
virtual void
|
||||
SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
NoteClosedAfterForget(const nsID& aId) MOZ_OVERRIDE;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void
|
||||
AssertOwningThread() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
// PCacheStreamControlChild methods
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) MOZ_OVERRIDE;
|
||||
virtual bool RecvClose(const nsID& aId) MOZ_OVERRIDE;
|
||||
virtual bool RecvCloseAll() MOZ_OVERRIDE;
|
||||
|
||||
typedef nsTObserverArray<ReadStream*> ReadStreamList;
|
||||
ReadStreamList mListeners;
|
||||
|
||||
bool mDestroyStarted;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
99
dom/cache/CacheStreamControlParent.cpp
vendored
99
dom/cache/CacheStreamControlParent.cpp
vendored
@ -8,14 +8,23 @@
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/StreamList.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetParent.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::FileDescriptorSetParent;
|
||||
using mozilla::ipc::OptionalFileDescriptorSet;
|
||||
using mozilla::ipc::PFileDescriptorSetParent;
|
||||
|
||||
// declared in ActorUtils.h
|
||||
void
|
||||
DeallocPCacheStreamControlParent(PCacheStreamControlParent* aActor)
|
||||
@ -36,33 +45,75 @@ CacheStreamControlParent::~CacheStreamControlParent()
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::AddListener(ReadStream* aListener)
|
||||
CacheStreamControlParent::SerializeControl(PCacheReadStream* aReadStreamOut)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ASSERT(!mListeners.Contains(aListener));
|
||||
mListeners.AppendElement(aListener);
|
||||
aReadStreamOut->controlChild() = nullptr;
|
||||
aReadStreamOut->controlParent() = this;
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::RemoveListener(ReadStream* aListener)
|
||||
CacheStreamControlParent::SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<FileDescriptor>& aFds)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
MOZ_ASSERT(aListener);
|
||||
DebugOnly<bool> removed = mListeners.RemoveElement(aListener);
|
||||
MOZ_ASSERT(removed);
|
||||
PFileDescriptorSetParent* fdSet = nullptr;
|
||||
if (!aFds.IsEmpty()) {
|
||||
fdSet = Manager()->SendPFileDescriptorSetConstructor(aFds[0]);
|
||||
for (uint32_t i = 1; i < aFds.Length(); ++i) {
|
||||
unused << fdSet->SendAddFileDescriptor(aFds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fdSet) {
|
||||
aReadStreamOut->fds() = fdSet;
|
||||
} else {
|
||||
aReadStreamOut->fds() = void_t();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
nsTArray<FileDescriptor>& aFdsOut)
|
||||
{
|
||||
if (aReadStream.fds().type() !=
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileDescriptorSetParent* fdSetActor =
|
||||
static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(aFdsOut);
|
||||
MOZ_ASSERT(!aFdsOut.IsEmpty());
|
||||
|
||||
if (!fdSetActor->Send__delete__(fdSetActor)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to delete fd set actor.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::NoteClosedAfterForget(const nsID& aId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
RecvNoteClosed(aId);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
CacheStreamControlParent::AssertOwningThread()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
CacheStreamControlParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
MOZ_ASSERT(mStreamList);
|
||||
ReadStreamList::ForwardIterator iter(mListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream> stream = iter.GetNext();
|
||||
stream->CloseStreamWithoutReporting();
|
||||
}
|
||||
CloseAllReadStreamsWithoutReporting();
|
||||
mStreamList->RemoveStreamControl(this);
|
||||
mStreamList->NoteClosedAll();
|
||||
mStreamList = nullptr;
|
||||
@ -116,30 +167,14 @@ void
|
||||
CacheStreamControlParent::NotifyClose(const nsID& aId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
DebugOnly<uint32_t> closedCount = 0;
|
||||
|
||||
ReadStreamList::ForwardIterator iter(mListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream> stream = iter.GetNext();
|
||||
// note, multiple streams may exist for same ID
|
||||
if (stream->MatchId(aId)) {
|
||||
stream->CloseStream();
|
||||
closedCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(closedCount > 0);
|
||||
CloseReadStreams(aId);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::NotifyCloseAll()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
ReadStreamList::ForwardIterator iter(mListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream> stream = iter.GetNext();
|
||||
stream->CloseStream();
|
||||
}
|
||||
CloseAllReadStreams();
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
30
dom/cache/CacheStreamControlParent.h
vendored
30
dom/cache/CacheStreamControlParent.h
vendored
@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_cache_CacheStreamControlParent_h
|
||||
|
||||
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/StreamControl.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -18,24 +19,42 @@ class ReadStream;
|
||||
class StreamList;
|
||||
|
||||
class CacheStreamControlParent : public PCacheStreamControlParent
|
||||
, public StreamControl
|
||||
{
|
||||
public:
|
||||
CacheStreamControlParent();
|
||||
~CacheStreamControlParent();
|
||||
|
||||
void AddListener(ReadStream* aListener);
|
||||
void RemoveListener(ReadStream* aListener);
|
||||
|
||||
void SetStreamList(StreamList* aStreamList);
|
||||
void Close(const nsID& aId);
|
||||
void CloseAll();
|
||||
void Shutdown();
|
||||
|
||||
// StreamControl methods
|
||||
virtual void
|
||||
SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
NoteClosedAfterForget(const nsID& aId) MOZ_OVERRIDE;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void
|
||||
AssertOwningThread() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
// PCacheStreamControlParent methods
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) MOZ_OVERRIDE;
|
||||
virtual bool RecvNoteClosed(const nsID& aId) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
void NotifyClose(const nsID& aId);
|
||||
void NotifyCloseAll();
|
||||
|
||||
@ -44,9 +63,6 @@ private:
|
||||
// StreamList::RemoveStreamControl() to clear the weak ref.
|
||||
nsRefPtr<StreamList> mStreamList;
|
||||
|
||||
typedef nsTObserverArray<ReadStream*> ReadStreamList;
|
||||
ReadStreamList mListeners;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
|
699
dom/cache/ReadStream.cpp
vendored
699
dom/cache/ReadStream.cpp
vendored
@ -9,234 +9,121 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlChild.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/PCacheStreamControlChild.h"
|
||||
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/InputStreamParams.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetParent.h"
|
||||
#include "mozilla/SnappyUncompressInputStream.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using mozilla::unused;
|
||||
using mozilla::void_t;
|
||||
using mozilla::dom::cache::CacheStreamControlChild;
|
||||
using mozilla::dom::cache::CacheStreamControlParent;
|
||||
using mozilla::dom::cache::PCacheReadStream;
|
||||
using mozilla::dom::cache::PCacheStreamControlChild;
|
||||
using mozilla::dom::cache::PCacheStreamControlParent;
|
||||
using mozilla::dom::cache::ReadStream;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::PFileDescriptorSetChild;
|
||||
using mozilla::ipc::PFileDescriptorSetParent;
|
||||
|
||||
// There are separate concrete implementations of ReadStream for the child
|
||||
// and parent processes. This is unfortunately necessary because the
|
||||
// actor types are distinct for these two cases. Also, the interface for
|
||||
// reporting the close event differs slightly for the child and parent
|
||||
// StreamControl actors.
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class ReadStreamChild MOZ_FINAL : public ReadStream
|
||||
{
|
||||
public:
|
||||
ReadStreamChild(PCacheStreamControlChild* aControl, const nsID& aId,
|
||||
nsIInputStream* aStream)
|
||||
: ReadStream(aId, aStream)
|
||||
, mControl(static_cast<CacheStreamControlChild*>(aControl))
|
||||
{
|
||||
MOZ_ASSERT(mControl);
|
||||
mControl->AddListener(this);
|
||||
}
|
||||
|
||||
virtual ~ReadStreamChild()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
NoteClosed();
|
||||
}
|
||||
|
||||
virtual void NoteClosedOnOwningThread() MOZ_OVERRIDE
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
mControl->RemoveListener(this);
|
||||
mControl->NoteClosed(mId);
|
||||
}
|
||||
|
||||
virtual void ForgetOnOwningThread() MOZ_OVERRIDE
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
mControl->RemoveListener(this);
|
||||
}
|
||||
|
||||
virtual void SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
aReadStreamOut->controlParent() = nullptr;
|
||||
aReadStreamOut->controlChild() = mControl;
|
||||
}
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<FileDescriptor>& fds) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!mClosed);
|
||||
PFileDescriptorSetChild* fdSet = nullptr;
|
||||
if (!fds.IsEmpty()) {
|
||||
fdSet = mControl->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
for (uint32_t i = 1; i < fds.Length(); ++i) {
|
||||
unused << fdSet->SendAddFileDescriptor(fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fdSet) {
|
||||
aReadStreamOut->fds() = fdSet;
|
||||
} else {
|
||||
aReadStreamOut->fds() = void_t();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CacheStreamControlChild* mControl;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class ReadStreamParent MOZ_FINAL : public ReadStream
|
||||
{
|
||||
public:
|
||||
ReadStreamParent(PCacheStreamControlParent* aControl, const nsID& aId,
|
||||
nsIInputStream* aStream)
|
||||
: ReadStream(aId, aStream)
|
||||
, mControl(static_cast<CacheStreamControlParent*>(aControl))
|
||||
{
|
||||
MOZ_ASSERT(mControl);
|
||||
mControl->AddListener(this);
|
||||
}
|
||||
|
||||
virtual ~ReadStreamParent()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
NoteClosed();
|
||||
}
|
||||
|
||||
virtual void NoteClosedOnOwningThread() MOZ_OVERRIDE
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
mControl->RemoveListener(this);
|
||||
// This can cause mControl to be destructed
|
||||
mControl->RecvNoteClosed(mId);
|
||||
mControl = nullptr;
|
||||
}
|
||||
|
||||
virtual void ForgetOnOwningThread() MOZ_OVERRIDE
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
// This can cause mControl to be destroyed
|
||||
mControl->RemoveListener(this);
|
||||
mControl = nullptr;
|
||||
}
|
||||
|
||||
virtual void SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(mControl);
|
||||
aReadStreamOut->controlChild() = nullptr;
|
||||
aReadStreamOut->controlParent() = mControl;
|
||||
}
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<FileDescriptor>& fds) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(mControl);
|
||||
PFileDescriptorSetParent* fdSet = nullptr;
|
||||
if (!fds.IsEmpty()) {
|
||||
fdSet = mControl->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
for (uint32_t i = 1; i < fds.Length(); ++i) {
|
||||
unused << fdSet->SendAddFileDescriptor(fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fdSet) {
|
||||
aReadStreamOut->fds() = fdSet;
|
||||
} else {
|
||||
aReadStreamOut->fds() = void_t();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CacheStreamControlParent* mControl;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::unused;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::FileDescriptorSetChild;
|
||||
using mozilla::ipc::FileDescriptorSetParent;
|
||||
using mozilla::ipc::InputStreamParams;
|
||||
using mozilla::ipc::OptionalFileDescriptorSet;
|
||||
using mozilla::ipc::PFileDescriptorSetChild;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// The inner stream class. This is where all of the real work is done. As
|
||||
// an invariant Inner::Close() must be called before ~Inner(). This is
|
||||
// guaranteed by our outer ReadStream class.
|
||||
class ReadStream::Inner MOZ_FINAL : public ReadStream::Controllable
|
||||
{
|
||||
public:
|
||||
Inner(StreamControl* aControl, const nsID& aId,
|
||||
nsIInputStream* aStream);
|
||||
|
||||
void
|
||||
Serialize(PCacheReadStreamOrVoid* aReadStreamOut);
|
||||
|
||||
void
|
||||
Serialize(PCacheReadStream* aReadStreamOut);
|
||||
|
||||
// ReadStream::Controllable methods
|
||||
virtual void
|
||||
CloseStream() MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
CloseStreamWithoutReporting() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
MatchId(const nsID& aId) const MOZ_OVERRIDE;
|
||||
|
||||
// Simulate nsIInputStream methods, but we don't actually inherit from it
|
||||
NS_METHOD
|
||||
Close();
|
||||
|
||||
NS_METHOD
|
||||
Available(uint64_t *aNumAvailableOut);
|
||||
|
||||
NS_METHOD
|
||||
Read(char *aBuf, uint32_t aCount, uint32_t *aNumReadOut);
|
||||
|
||||
NS_METHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount,
|
||||
uint32_t *aNumReadOut);
|
||||
|
||||
NS_METHOD
|
||||
IsNonBlocking(bool *aNonBlockingOut);
|
||||
|
||||
private:
|
||||
class NoteClosedRunnable;
|
||||
class ForgetRunnable;
|
||||
|
||||
~Inner();
|
||||
|
||||
void
|
||||
NoteClosed();
|
||||
|
||||
void
|
||||
Forget();
|
||||
|
||||
void
|
||||
NoteClosedOnOwningThread();
|
||||
|
||||
void
|
||||
ForgetOnOwningThread();
|
||||
|
||||
// Weak ref to the stream control actor. The actor will always call either
|
||||
// CloseStream() or CloseStreamWithoutReporting() before it's destroyed. The
|
||||
// weak ref is cleared in the resulting NoteClosedOnOwningThread() or
|
||||
// ForgetOnOwningThread() method call.
|
||||
StreamControl* mControl;
|
||||
|
||||
const nsID mId;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsIInputStream> mSnappyStream;
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
|
||||
enum State
|
||||
{
|
||||
Open,
|
||||
Closed,
|
||||
NumStates
|
||||
};
|
||||
Atomic<State> mState;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(cache::ReadStream::Inner)
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Runnable to notify actors that the ReadStream has closed. This must
|
||||
// be done on the thread associated with the PBackground actor. Must be
|
||||
// cancelable to execute on Worker threads (which can occur when the
|
||||
// ReadStream is constructed on a child process Worker thread).
|
||||
class ReadStream::NoteClosedRunnable MOZ_FINAL : public nsCancelableRunnable
|
||||
class ReadStream::Inner::NoteClosedRunnable MOZ_FINAL : public nsCancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit NoteClosedRunnable(ReadStream* aStream)
|
||||
explicit NoteClosedRunnable(ReadStream::Inner* aStream)
|
||||
: mStream(aStream)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mStream->NoteClosedOnOwningThread();
|
||||
mStream = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -251,24 +138,27 @@ public:
|
||||
private:
|
||||
~NoteClosedRunnable() { }
|
||||
|
||||
nsRefPtr<ReadStream> mStream;
|
||||
nsRefPtr<ReadStream::Inner> mStream;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Runnable to clear actors without reporting that the ReadStream has
|
||||
// closed. Since this can trigger actor destruction, we need to do
|
||||
// it on the thread associated with the PBackground actor. Must be
|
||||
// cancelable to execute on Worker threads (which can occur when the
|
||||
// ReadStream is constructed on a child process Worker thread).
|
||||
class ReadStream::ForgetRunnable MOZ_FINAL : public nsCancelableRunnable
|
||||
class ReadStream::Inner::ForgetRunnable MOZ_FINAL : public nsCancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit ForgetRunnable(ReadStream* aStream)
|
||||
explicit ForgetRunnable(ReadStream::Inner* aStream)
|
||||
: mStream(aStream)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mStream->ForgetOnOwningThread();
|
||||
mStream = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -283,11 +173,216 @@ public:
|
||||
private:
|
||||
~ForgetRunnable() { }
|
||||
|
||||
nsRefPtr<ReadStream> mStream;
|
||||
nsRefPtr<ReadStream::Inner> mStream;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(mozilla::dom::cache::ReadStream, nsIInputStream,
|
||||
ReadStream);
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
ReadStream::Inner::Inner(StreamControl* aControl, const nsID& aId,
|
||||
nsIInputStream* aStream)
|
||||
: mControl(aControl)
|
||||
, mId(aId)
|
||||
, mStream(aStream)
|
||||
, mSnappyStream(new SnappyUncompressInputStream(aStream))
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
, mState(Open)
|
||||
{
|
||||
MOZ_ASSERT(mStream);
|
||||
MOZ_ASSERT(mControl);
|
||||
mControl->AddReadStream(this);
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::Serialize(PCacheReadStreamOrVoid* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
PCacheReadStream stream;
|
||||
Serialize(&stream);
|
||||
*aReadStreamOut = stream;
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::Serialize(PCacheReadStream* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
MOZ_ASSERT(mState == Open);
|
||||
MOZ_ASSERT(mControl);
|
||||
|
||||
aReadStreamOut->id() = mId;
|
||||
mControl->SerializeControl(aReadStreamOut);
|
||||
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
SerializeInputStream(mStream, aReadStreamOut->params(), fds);
|
||||
|
||||
mControl->SerializeFds(aReadStreamOut, fds);
|
||||
|
||||
// We're passing ownership across the IPC barrier with the control, so
|
||||
// do not signal that the stream is closed here.
|
||||
Forget();
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::CloseStream()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
Close();
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::CloseStreamWithoutReporting()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
Forget();
|
||||
}
|
||||
|
||||
bool
|
||||
ReadStream::Inner::MatchId(const nsID& aId) const
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
return mId.Equals(aId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Inner::Close()
|
||||
{
|
||||
// stream ops can happen on any thread
|
||||
nsresult rv = mStream->Close();
|
||||
NoteClosed();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Inner::Available(uint64_t* aNumAvailableOut)
|
||||
{
|
||||
// stream ops can happen on any thread
|
||||
nsresult rv = mSnappyStream->Available(aNumAvailableOut);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Inner::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
|
||||
{
|
||||
// stream ops can happen on any thread
|
||||
MOZ_ASSERT(aNumReadOut);
|
||||
|
||||
nsresult rv = mSnappyStream->Read(aBuf, aCount, aNumReadOut);
|
||||
|
||||
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) ||
|
||||
*aNumReadOut == 0) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Inner::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* aNumReadOut)
|
||||
{
|
||||
// stream ops can happen on any thread
|
||||
MOZ_ASSERT(aNumReadOut);
|
||||
|
||||
nsresult rv = mSnappyStream->ReadSegments(aWriter, aClosure, aCount,
|
||||
aNumReadOut);
|
||||
|
||||
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK &&
|
||||
rv != NS_ERROR_NOT_IMPLEMENTED) || *aNumReadOut == 0) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Inner::IsNonBlocking(bool* aNonBlockingOut)
|
||||
{
|
||||
// stream ops can happen on any thread
|
||||
return mSnappyStream->IsNonBlocking(aNonBlockingOut);
|
||||
}
|
||||
|
||||
ReadStream::Inner::~Inner()
|
||||
{
|
||||
// Any thread
|
||||
MOZ_ASSERT(mState == Closed);
|
||||
MOZ_ASSERT(!mControl);
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::NoteClosed()
|
||||
{
|
||||
// Any thread
|
||||
if (mState == Closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_GetCurrentThread() == mOwningThread) {
|
||||
NoteClosedOnOwningThread();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new NoteClosedRunnable(this);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)));
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::Forget()
|
||||
{
|
||||
// Any thread
|
||||
if (mState == Closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_GetCurrentThread() == mOwningThread) {
|
||||
ForgetOnOwningThread();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new ForgetRunnable(this);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)));
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::NoteClosedOnOwningThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
|
||||
// Mark closed and do nothing if we were already closed
|
||||
if (!mState.compareExchange(Open, Closed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mControl);
|
||||
mControl->NoteClosed(this, mId);
|
||||
mControl = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::ForgetOnOwningThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
|
||||
// Mark closed and do nothing if we were already closed
|
||||
if (!mState.compareExchange(Open, Closed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mControl);
|
||||
mControl->ForgetReadStream(this);
|
||||
mControl = nullptr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS(cache::ReadStream, nsIInputStream, ReadStream);
|
||||
|
||||
// static
|
||||
already_AddRefed<ReadStream>
|
||||
@ -311,33 +406,20 @@ ReadStream::Create(const PCacheReadStream& aReadStream)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
if (aReadStream.fds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
|
||||
FileDescriptorSetChild* fdSetActor =
|
||||
static_cast<FileDescriptorSetChild*>(aReadStream.fds().get_PFileDescriptorSetChild());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
} else if (aReadStream.fds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
|
||||
|
||||
FileDescriptorSetParent* fdSetActor =
|
||||
static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
if (!fdSetActor->Send__delete__(fdSetActor)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to delete fd set actor.");
|
||||
}
|
||||
// Control is guaranteed to survive this method as ActorDestroy() cannot
|
||||
// run on this thread until we complete.
|
||||
StreamControl* control;
|
||||
if (aReadStream.controlChild()) {
|
||||
auto actor = static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
|
||||
control = actor;
|
||||
} else {
|
||||
auto actor = static_cast<CacheStreamControlParent*>(aReadStream.controlParent());
|
||||
control = actor;
|
||||
}
|
||||
MOZ_ASSERT(control);
|
||||
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
control->DeserializeFds(aReadStream, fds);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream =
|
||||
DeserializeInputStream(aReadStream.params(), fds);
|
||||
@ -349,16 +431,8 @@ ReadStream::Create(const PCacheReadStream& aReadStream)
|
||||
MOZ_ASSERT(!asyncStream);
|
||||
#endif
|
||||
|
||||
nsRefPtr<ReadStream> ref;
|
||||
|
||||
if (aReadStream.controlChild()) {
|
||||
ref = new ReadStreamChild(aReadStream.controlChild(), aReadStream.id(),
|
||||
stream);
|
||||
} else {
|
||||
ref = new ReadStreamParent(aReadStream.controlParent(), aReadStream.id(),
|
||||
stream);
|
||||
}
|
||||
|
||||
nsRefPtr<Inner> inner = new Inner(control, aReadStream.id(), stream);
|
||||
nsRefPtr<ReadStream> ref = new ReadStream(inner);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
@ -367,170 +441,67 @@ already_AddRefed<ReadStream>
|
||||
ReadStream::Create(PCacheStreamControlParent* aControl, const nsID& aId,
|
||||
nsIInputStream* aStream)
|
||||
{
|
||||
nsRefPtr<ReadStream> ref = new ReadStreamParent(aControl, aId, aStream);
|
||||
MOZ_ASSERT(aControl);
|
||||
auto actor = static_cast<CacheStreamControlParent*>(aControl);
|
||||
nsRefPtr<Inner> inner = new Inner(actor, aId, aStream);
|
||||
nsRefPtr<ReadStream> ref = new ReadStream(inner);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Serialize(PCacheReadStreamOrVoid* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
PCacheReadStream stream;
|
||||
Serialize(&stream);
|
||||
*aReadStreamOut = stream;
|
||||
mInner->Serialize(aReadStreamOut);
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Serialize(PCacheReadStream* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
|
||||
aReadStreamOut->id() = mId;
|
||||
SerializeControl(aReadStreamOut);
|
||||
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
SerializeInputStream(mStream, aReadStreamOut->params(), fds);
|
||||
|
||||
SerializeFds(aReadStreamOut, fds);
|
||||
|
||||
// We're passing ownership across the IPC barrier with the control, so
|
||||
// do not signal that the stream is closed here.
|
||||
Forget();
|
||||
mInner->Serialize(aReadStreamOut);
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::CloseStream()
|
||||
ReadStream::ReadStream(ReadStream::Inner* aInner)
|
||||
: mInner(aInner)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::CloseStreamWithoutReporting()
|
||||
{
|
||||
Forget();
|
||||
}
|
||||
|
||||
bool
|
||||
ReadStream::MatchId(const nsID& aId) const
|
||||
{
|
||||
return mId.Equals(aId);
|
||||
}
|
||||
|
||||
ReadStream::ReadStream(const nsID& aId, nsIInputStream* aStream)
|
||||
: mId(aId)
|
||||
, mStream(aStream)
|
||||
, mSnappyStream(new SnappyUncompressInputStream(aStream))
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
, mClosed(false)
|
||||
{
|
||||
MOZ_ASSERT(mStream);
|
||||
MOZ_ASSERT(mInner);
|
||||
}
|
||||
|
||||
ReadStream::~ReadStream()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ReadStream);
|
||||
|
||||
// We cannot directly call NoteClosed() here. The concrete subclasses
|
||||
// destructors must do this because it takes code paths through virtual
|
||||
// methods. We don't want to execute these while partially destroyed.
|
||||
MOZ_ASSERT(mClosed);
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::NoteClosed()
|
||||
{
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_GetCurrentThread() == mOwningThread) {
|
||||
NoteClosedOnOwningThread();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new NoteClosedRunnable(this);
|
||||
nsresult rv = mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch Cache ReadStream NoteClosed() runnable.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Forget()
|
||||
{
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_GetCurrentThread() == mOwningThread) {
|
||||
ForgetOnOwningThread();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new ForgetRunnable(this);
|
||||
nsresult rv = mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch Cache ReadStream Forget() runnable.");
|
||||
}
|
||||
// Explicitly close the inner stream so that it does not have to
|
||||
// deal with implicitly closing at destruction time.
|
||||
mInner->Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Close()
|
||||
{
|
||||
nsresult rv = mStream->Close();
|
||||
NoteClosed();
|
||||
return rv;
|
||||
return mInner->Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Available(uint64_t* aNumAvailableOut)
|
||||
{
|
||||
nsresult rv = mSnappyStream->Available(aNumAvailableOut);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return rv;
|
||||
return mInner->Available(aNumAvailableOut);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
|
||||
{
|
||||
MOZ_ASSERT(aNumReadOut);
|
||||
|
||||
nsresult rv = mSnappyStream->Read(aBuf, aCount, aNumReadOut);
|
||||
|
||||
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) ||
|
||||
*aNumReadOut == 0) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return rv;
|
||||
return mInner->Read(aBuf, aCount, aNumReadOut);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* aNumReadOut)
|
||||
{
|
||||
MOZ_ASSERT(aNumReadOut);
|
||||
|
||||
nsresult rv = mSnappyStream->ReadSegments(aWriter, aClosure, aCount,
|
||||
aNumReadOut);
|
||||
|
||||
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK &&
|
||||
rv != NS_ERROR_NOT_IMPLEMENTED) || *aNumReadOut == 0) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return rv;
|
||||
return mInner->ReadSegments(aWriter, aClosure, aCount, aNumReadOut);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::IsNonBlocking(bool* aNonBlockingOut)
|
||||
{
|
||||
return mSnappyStream->IsNonBlocking(aNonBlockingOut);
|
||||
return mInner->IsNonBlocking(aNonBlockingOut);
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
67
dom/cache/ReadStream.h
vendored
67
dom/cache/ReadStream.h
vendored
@ -12,6 +12,7 @@
|
||||
#include "nsID.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
|
||||
class nsIThread;
|
||||
@ -29,6 +30,7 @@ class PCacheStreamControlParent;
|
||||
{0x8e5da7c9, 0x0940, 0x4f1d, \
|
||||
{0x97, 0x25, 0x5c, 0x59, 0x38, 0xdd, 0xb9, 0x9f}}
|
||||
|
||||
|
||||
// Custom stream class for Request and Response bodies being read from
|
||||
// a Cache. The main purpose of this class is to report back to the
|
||||
// Cache's Manager when the stream is closed. This allows the Cache to
|
||||
@ -40,9 +42,34 @@ class PCacheStreamControlParent;
|
||||
// stream channel. For example, Cache.put() can detect that the content
|
||||
// script is passing a Cache-originated-stream back into the Cache
|
||||
// again. This enables certain optimizations.
|
||||
class ReadStream : public nsIInputStream
|
||||
class ReadStream MOZ_FINAL : public nsIInputStream
|
||||
{
|
||||
public:
|
||||
// Interface that lets the StreamControl classes interact with
|
||||
// our private inner stream.
|
||||
class Controllable
|
||||
{
|
||||
public:
|
||||
// Closes the stream, notifies the stream control, and then forgets
|
||||
// the stream control.
|
||||
virtual void
|
||||
CloseStream() = 0;
|
||||
|
||||
// Closes the stream and then forgets the stream control. Does not
|
||||
// notify.
|
||||
virtual void
|
||||
CloseStreamWithoutReporting() = 0;
|
||||
|
||||
virtual bool
|
||||
MatchId(const nsID& aId) const = 0;
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType)
|
||||
AddRef(void) = 0;
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType)
|
||||
Release(void) = 0;
|
||||
};
|
||||
|
||||
static already_AddRefed<ReadStream>
|
||||
Create(const PCacheReadStreamOrVoid& aReadStreamOrVoid);
|
||||
|
||||
@ -56,39 +83,21 @@ public:
|
||||
void Serialize(PCacheReadStreamOrVoid* aReadStreamOut);
|
||||
void Serialize(PCacheReadStream* aReadStreamOut);
|
||||
|
||||
// methods called from the child and parent CacheStreamControl actors
|
||||
void CloseStream();
|
||||
void CloseStreamWithoutReporting();
|
||||
bool MatchId(const nsID& aId) const;
|
||||
private:
|
||||
class Inner;
|
||||
|
||||
protected:
|
||||
class NoteClosedRunnable;
|
||||
class ForgetRunnable;
|
||||
explicit ReadStream(Inner* aInner);
|
||||
~ReadStream();
|
||||
|
||||
ReadStream(const nsID& aId, nsIInputStream* aStream);
|
||||
virtual ~ReadStream();
|
||||
|
||||
void NoteClosed();
|
||||
void Forget();
|
||||
|
||||
virtual void NoteClosedOnOwningThread() = 0;
|
||||
virtual void ForgetOnOwningThread() = 0;
|
||||
virtual void SerializeControl(PCacheReadStream* aReadStreamOut) = 0;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& fds) = 0;
|
||||
|
||||
const nsID mId;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsIInputStream> mSnappyStream;
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
bool mClosed;
|
||||
// Hold a strong ref to an inner class that actually implements the
|
||||
// majority of the stream logic. Before releasing this ref the outer
|
||||
// ReadStream guarantees it will call Close() on the inner stream.
|
||||
// This is essential for the inner stream to avoid dealing with the
|
||||
// implicit close that can happen when a stream is destroyed.
|
||||
nsRefPtr<Inner> mInner;
|
||||
|
||||
public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_CACHE_READSTREAM_IID);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
};
|
||||
|
89
dom/cache/StreamControl.cpp
vendored
Normal file
89
dom/cache/StreamControl.cpp
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/cache/StreamControl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
void
|
||||
StreamControl::AddReadStream(ReadStream::Controllable* aReadStream)
|
||||
{
|
||||
AssertOwningThread();
|
||||
MOZ_ASSERT(aReadStream);
|
||||
MOZ_ASSERT(!mReadStreamList.Contains(aReadStream));
|
||||
mReadStreamList.AppendElement(aReadStream);
|
||||
}
|
||||
|
||||
void
|
||||
StreamControl::ForgetReadStream(ReadStream::Controllable* aReadStream)
|
||||
{
|
||||
AssertOwningThread();
|
||||
MOZ_ALWAYS_TRUE(mReadStreamList.RemoveElement(aReadStream));
|
||||
}
|
||||
|
||||
void
|
||||
StreamControl::NoteClosed(ReadStream::Controllable* aReadStream,
|
||||
const nsID& aId)
|
||||
{
|
||||
AssertOwningThread();
|
||||
ForgetReadStream(aReadStream);
|
||||
NoteClosedAfterForget(aId);
|
||||
}
|
||||
|
||||
StreamControl::~StreamControl()
|
||||
{
|
||||
// owning thread only, but can't call virtual AssertOwningThread in destructor
|
||||
MOZ_ASSERT(mReadStreamList.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
StreamControl::CloseReadStreams(const nsID& aId)
|
||||
{
|
||||
AssertOwningThread();
|
||||
DebugOnly<uint32_t> closedCount = 0;
|
||||
|
||||
ReadStreamList::ForwardIterator iter(mReadStreamList);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream::Controllable> stream = iter.GetNext();
|
||||
if (stream->MatchId(aId)) {
|
||||
stream->CloseStream();
|
||||
closedCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(closedCount > 0);
|
||||
}
|
||||
|
||||
void
|
||||
StreamControl::CloseAllReadStreams()
|
||||
{
|
||||
AssertOwningThread();
|
||||
|
||||
ReadStreamList::ForwardIterator iter(mReadStreamList);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->CloseStream();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StreamControl::CloseAllReadStreamsWithoutReporting()
|
||||
{
|
||||
AssertOwningThread();
|
||||
|
||||
ReadStreamList::ForwardIterator iter(mReadStreamList);
|
||||
while (iter.HasMore()) {
|
||||
nsRefPtr<ReadStream::Controllable> stream = iter.GetNext();
|
||||
// Note, we cannot trigger IPC traffic here. So use
|
||||
// CloseStreamWithoutReporting().
|
||||
stream->CloseStreamWithoutReporting();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
93
dom/cache/StreamControl.h
vendored
Normal file
93
dom/cache/StreamControl.h
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 mozilla_dom_cache_StreamControl_h
|
||||
#define mozilla_dom_cache_StreamControl_h
|
||||
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
struct nsID;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class FileDescriptor;
|
||||
}
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class PCacheReadStream;
|
||||
|
||||
// Abstract class to help implement the stream control Child and Parent actors.
|
||||
// This provides an interface to partly help with serialization of IPC types,
|
||||
// but also an implementation for tracking ReadStream objects.
|
||||
class StreamControl
|
||||
{
|
||||
public:
|
||||
// abstract interface that must be implemented by child class
|
||||
virtual void
|
||||
SerializeControl(PCacheReadStream* aReadStreamOut) = 0;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) = 0;
|
||||
|
||||
virtual void
|
||||
DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) = 0;
|
||||
|
||||
// inherited implementation of the ReadStream::Controllable list
|
||||
|
||||
// Begin controlling the given ReadStream. This causes a strong ref to
|
||||
// be held by the control. The ReadStream must call NoteClosed() or
|
||||
// ForgetReadStream() to release this ref.
|
||||
void
|
||||
AddReadStream(ReadStream::Controllable* aReadStream);
|
||||
|
||||
// Forget the ReadStream without notifying the actor.
|
||||
void
|
||||
ForgetReadStream(ReadStream::Controllable* aReadStream);
|
||||
|
||||
// Forget the ReadStream and then notify the actor the stream is closed.
|
||||
void
|
||||
NoteClosed(ReadStream::Controllable* aReadStream, const nsID& aId);
|
||||
|
||||
protected:
|
||||
~StreamControl();
|
||||
|
||||
void
|
||||
CloseReadStreams(const nsID& aId);
|
||||
|
||||
void
|
||||
CloseAllReadStreams();
|
||||
|
||||
void
|
||||
CloseAllReadStreamsWithoutReporting();
|
||||
|
||||
// protected parts of the abstract interface
|
||||
virtual void
|
||||
NoteClosedAfterForget(const nsID& aId) = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void
|
||||
AssertOwningThread() = 0;
|
||||
#else
|
||||
void AssertOwningThread() { }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Hold strong references to ReadStream object. When the stream is closed
|
||||
// it should call NoteClosed() or ForgetReadStream() to release this ref.
|
||||
typedef nsTObserverArray<nsRefPtr<ReadStream::Controllable>> ReadStreamList;
|
||||
ReadStreamList mReadStreamList;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_cache_StreamControl_h
|
2
dom/cache/moz.build
vendored
2
dom/cache/moz.build
vendored
@ -30,6 +30,7 @@ EXPORTS.mozilla.dom.cache += [
|
||||
'QuotaClient.h',
|
||||
'ReadStream.h',
|
||||
'SavedTypes.h',
|
||||
'StreamControl.h',
|
||||
'StreamList.h',
|
||||
'StreamUtils.h',
|
||||
'Types.h',
|
||||
@ -59,6 +60,7 @@ UNIFIED_SOURCES += [
|
||||
'PrincipalVerifier.cpp',
|
||||
'QuotaClient.cpp',
|
||||
'ReadStream.cpp',
|
||||
'StreamControl.cpp',
|
||||
'StreamList.cpp',
|
||||
'StreamUtils.cpp',
|
||||
'TypeUtils.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user