Bug 1627892 - Make Context derive from SafeRefCounted. r=dom-workers-and-storage-reviewers,perry

Differential Revision: https://phabricator.services.mozilla.com/D69957
This commit is contained in:
Simon Giesecke 2020-05-11 12:09:55 +00:00
Родитель 33a08c2818
Коммит c4c6f0c42c
6 изменённых файлов: 111 добавлений и 104 удалений

63
dom/cache/Context.cpp поставляемый
Просмотреть файл

@ -88,11 +88,11 @@ class Context::Data final : public Action::Data {
class Context::QuotaInitRunnable final : public nsIRunnable,
public OpenDirectoryListener {
public:
QuotaInitRunnable(Context* aContext, SafeRefPtr<Manager> aManager,
QuotaInitRunnable(SafeRefPtr<Context> aContext, SafeRefPtr<Manager> aManager,
Data* aData, nsISerialEventTarget* aTarget,
Action* aInitAction)
: mContext(aContext),
mThreadsafeHandle(aContext->CreateThreadsafeHandle()),
: mContext(std::move(aContext)),
mThreadsafeHandle(mContext->CreateThreadsafeHandle()),
mManager(std::move(aManager)),
mData(aData),
mTarget(aTarget),
@ -198,7 +198,7 @@ class Context::QuotaInitRunnable final : public nsIRunnable,
mInitAction = nullptr;
}
RefPtr<Context> mContext;
SafeRefPtr<Context> mContext;
RefPtr<ThreadsafeHandle> mThreadsafeHandle;
SafeRefPtr<Manager> mManager;
RefPtr<Data> mData;
@ -462,9 +462,10 @@ class Context::ActionRunnable final : public nsIRunnable,
public Action::Resolver,
public Context::Activity {
public:
ActionRunnable(Context* aContext, Data* aData, nsISerialEventTarget* aTarget,
Action* aAction, const QuotaInfo& aQuotaInfo)
: mContext(aContext),
ActionRunnable(SafeRefPtr<Context> aContext, Data* aData,
nsISerialEventTarget* aTarget, Action* aAction,
const QuotaInfo& aQuotaInfo)
: mContext(std::move(aContext)),
mData(aData),
mTarget(aTarget),
mAction(aAction),
@ -553,7 +554,7 @@ class Context::ActionRunnable final : public nsIRunnable,
STATE_COMPLETE
};
RefPtr<Context> mContext;
SafeRefPtr<Context> mContext;
RefPtr<Data> mData;
nsCOMPtr<nsISerialEventTarget> mTarget;
RefPtr<Action> mAction;
@ -697,9 +698,9 @@ void Context::ThreadsafeHandle::InvalidateAndAllowToClose() {
nsIThread::DISPATCH_NORMAL));
}
Context::ThreadsafeHandle::ThreadsafeHandle(Context* aContext)
: mStrongRef(aContext),
mWeakRef(aContext),
Context::ThreadsafeHandle::ThreadsafeHandle(SafeRefPtr<Context> aContext)
: mStrongRef(std::move(aContext)),
mWeakRef(mStrongRef.unsafeGetRawPtr()),
mOwningEventTarget(GetCurrentThreadSerialEventTarget()) {}
Context::ThreadsafeHandle::~ThreadsafeHandle() {
@ -751,23 +752,23 @@ void Context::ThreadsafeHandle::InvalidateAndAllowToCloseOnOwningThread() {
MOZ_DIAGNOSTIC_ASSERT(!mStrongRef);
}
void Context::ThreadsafeHandle::ContextDestroyed(Context* aContext) {
void Context::ThreadsafeHandle::ContextDestroyed(Context& aContext) {
MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
MOZ_DIAGNOSTIC_ASSERT(!mStrongRef);
MOZ_DIAGNOSTIC_ASSERT(mWeakRef);
MOZ_DIAGNOSTIC_ASSERT(mWeakRef == aContext);
MOZ_DIAGNOSTIC_ASSERT(mWeakRef == &aContext);
mWeakRef = nullptr;
}
// static
already_AddRefed<Context> Context::Create(SafeRefPtr<Manager> aManager,
nsISerialEventTarget* aTarget,
Action* aInitAction,
Context* aOldContext) {
RefPtr<Context> context =
new Context(std::move(aManager), aTarget, aInitAction);
SafeRefPtr<Context> Context::Create(SafeRefPtr<Manager> aManager,
nsISerialEventTarget* aTarget,
Action* aInitAction,
Maybe<Context&> aOldContext) {
auto context =
MakeSafeRefPtr<Context>(std::move(aManager), aTarget, aInitAction);
context->Init(aOldContext);
return context.forget();
return context;
}
Context::Context(SafeRefPtr<Manager> aManager, nsISerialEventTarget* aTarget,
@ -870,11 +871,11 @@ Context::~Context() {
MOZ_DIAGNOSTIC_ASSERT(!mData);
if (mThreadsafeHandle) {
mThreadsafeHandle->ContextDestroyed(this);
mThreadsafeHandle->ContextDestroyed(*this);
}
// Note, this may set the mOrphanedData flag.
mManager->RemoveContext(this);
mManager->RemoveContext(*this);
if (mQuotaInfo.mDir && !mOrphanedData) {
MOZ_ALWAYS_SUCCEEDS(DeleteMarkerFile(mQuotaInfo));
@ -885,11 +886,11 @@ Context::~Context() {
}
}
void Context::Init(Context* aOldContext) {
void Context::Init(Maybe<Context&> aOldContext) {
NS_ASSERT_OWNINGTHREAD(Context);
if (aOldContext) {
aOldContext->SetNextContext(this);
aOldContext->SetNextContext(SafeRefPtrFromThis());
return;
}
@ -915,8 +916,8 @@ void Context::Start() {
MOZ_DIAGNOSTIC_ASSERT(mState == STATE_CONTEXT_PREINIT);
MOZ_DIAGNOSTIC_ASSERT(!mInitRunnable);
mInitRunnable = new QuotaInitRunnable(this, mManager.clonePtr(), mData,
mTarget, mInitAction);
mInitRunnable = new QuotaInitRunnable(
SafeRefPtrFromThis(), mManager.clonePtr(), mData, mTarget, mInitAction);
mInitAction = nullptr;
mState = STATE_CONTEXT_INIT;
@ -933,8 +934,8 @@ void Context::Start() {
void Context::DispatchAction(Action* aAction, bool aDoomData) {
NS_ASSERT_OWNINGTHREAD(Context);
RefPtr<ActionRunnable> runnable =
new ActionRunnable(this, mData, mTarget, aAction, mQuotaInfo);
RefPtr<ActionRunnable> runnable = new ActionRunnable(
SafeRefPtrFromThis(), mData, mTarget, aAction, mQuotaInfo);
if (aDoomData) {
mData = nullptr;
@ -1013,17 +1014,17 @@ void Context::NoteOrphanedData() {
already_AddRefed<Context::ThreadsafeHandle> Context::CreateThreadsafeHandle() {
NS_ASSERT_OWNINGTHREAD(Context);
if (!mThreadsafeHandle) {
mThreadsafeHandle = new ThreadsafeHandle(this);
mThreadsafeHandle = new ThreadsafeHandle(SafeRefPtrFromThis());
}
RefPtr<ThreadsafeHandle> ref = mThreadsafeHandle;
return ref.forget();
}
void Context::SetNextContext(Context* aNextContext) {
void Context::SetNextContext(SafeRefPtr<Context> aNextContext) {
NS_ASSERT_OWNINGTHREAD(Context);
MOZ_DIAGNOSTIC_ASSERT(aNextContext);
MOZ_DIAGNOSTIC_ASSERT(!mNextContext);
mNextContext = aNextContext;
mNextContext = std::move(aNextContext);
}
void Context::DoomTargetData() {

33
dom/cache/Context.h поставляемый
Просмотреть файл

@ -63,7 +63,7 @@ class Manager;
// As an invariant, all Context objects must be destroyed before permitting
// the "profile-before-change" shutdown event to complete. This is ensured
// via the code in ShutdownObserver.cpp.
class Context final {
class Context final : public SafeRefCounted<Context> {
typedef mozilla::dom::quota::DirectoryLock DirectoryLock;
public:
@ -77,7 +77,7 @@ class Context final {
void InvalidateAndAllowToClose();
private:
explicit ThreadsafeHandle(Context* aContext);
explicit ThreadsafeHandle(SafeRefPtr<Context> aContext);
~ThreadsafeHandle();
// disallow copying
@ -87,11 +87,11 @@ class Context final {
void AllowToCloseOnOwningThread();
void InvalidateAndAllowToCloseOnOwningThread();
void ContextDestroyed(Context* aContext);
void ContextDestroyed(Context& aContext);
// Cleared to allow the Context to close. Only safe to access on
// owning thread.
RefPtr<Context> mStrongRef;
SafeRefPtr<Context> mStrongRef;
// Used to support cancelation even while the Context is already allowed
// to close. Cleared by ~Context() calling ContextDestroyed(). Only
@ -117,10 +117,10 @@ class Context final {
// Create a Context attached to the given Manager. The given Action
// will run on the QuotaManager IO thread. Note, this Action must
// be execute synchronously.
static already_AddRefed<Context> Create(SafeRefPtr<Manager> aManager,
nsISerialEventTarget* aTarget,
Action* aInitAction,
Context* aOldContext);
static SafeRefPtr<Context> Create(SafeRefPtr<Manager> aManager,
nsISerialEventTarget* aTarget,
Action* aInitAction,
Maybe<Context&> aOldContext);
// Execute given action on the target once the quota manager has been
// initialized.
@ -178,10 +178,7 @@ class Context final {
RefPtr<Action> mAction;
};
Context(SafeRefPtr<Manager> aManager, nsISerialEventTarget* aTarget,
Action* aInitAction);
~Context();
void Init(Context* aOldContext);
void Init(Maybe<Context&> aOldContext);
void Start();
void DispatchAction(Action* aAction, bool aDoomData = false);
void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
@ -189,7 +186,7 @@ class Context final {
already_AddRefed<ThreadsafeHandle> CreateThreadsafeHandle();
void SetNextContext(Context* aNextContext);
void SetNextContext(SafeRefPtr<Context> aNextContext);
void DoomTargetData();
@ -214,10 +211,16 @@ class Context final {
RefPtr<ThreadsafeHandle> mThreadsafeHandle;
RefPtr<DirectoryLock> mDirectoryLock;
RefPtr<Context> mNextContext;
SafeRefPtr<Context> mNextContext;
public:
NS_INLINE_DECL_REFCOUNTING(cache::Context)
// XXX Consider adding a private guard parameter.
Context(SafeRefPtr<Manager> aManager, nsISerialEventTarget* aTarget,
Action* aInitAction);
~Context();
NS_DECL_OWNINGTHREAD
MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context)
};
} // namespace cache

108
dom/cache/Manager.cpp поставляемый
Просмотреть файл

@ -1415,15 +1415,16 @@ class Manager::StorageDeleteAction final : public Manager::BaseAction {
// deleted later.
if (!mManager->SetCacheIdOrphanedIfRefed(mCacheId)) {
// no outstanding references, delete immediately
RefPtr<Context> context = mManager->mContext;
const auto pinnedContext =
SafeRefPtr{mManager->mContext, AcquireStrongRefFromRawPtr{}};
if (context->IsCanceled()) {
context->NoteOrphanedData();
if (pinnedContext->IsCanceled()) {
pinnedContext->NoteOrphanedData();
} else {
context->CancelForCacheId(mCacheId);
pinnedContext->CancelForCacheId(mCacheId);
RefPtr<Action> action =
new DeleteOrphanedCacheAction(mManager.clonePtr(), mCacheId);
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
}
}
@ -1587,10 +1588,10 @@ void Manager::RemoveListener(Listener* aListener) {
MaybeAllowContextToClose();
}
void Manager::RemoveContext(Context* aContext) {
void Manager::RemoveContext(Context& aContext) {
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_DIAGNOSTIC_ASSERT(mContext);
MOZ_DIAGNOSTIC_ASSERT(mContext == aContext);
MOZ_DIAGNOSTIC_ASSERT(mContext == &aContext);
// Whether the Context destruction was triggered from the Manager going
// idle or the underlying storage being invalidated, we should know we
@ -1602,14 +1603,14 @@ void Manager::RemoveContext(Context* aContext) {
// orphaned data so it will be cleaned up on the next open.
for (uint32_t i = 0; i < mCacheIdRefs.Length(); ++i) {
if (mCacheIdRefs[i].mOrphaned) {
aContext->NoteOrphanedData();
aContext.NoteOrphanedData();
break;
}
}
for (uint32_t i = 0; i < mBodyIdRefs.Length(); ++i) {
if (mBodyIdRefs[i].mOrphaned) {
aContext->NoteOrphanedData();
aContext.NoteOrphanedData();
break;
}
}
@ -1659,17 +1660,18 @@ void Manager::ReleaseCacheId(CacheId aCacheId) {
if (mCacheIdRefs[i].mCount == 0) {
bool orphaned = mCacheIdRefs[i].mOrphaned;
mCacheIdRefs.RemoveElementAt(i);
RefPtr<Context> context = mContext;
const auto pinnedContext =
SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
// If the context is already gone, then orphan flag should have been
// set in RemoveContext().
if (orphaned && context) {
if (context->IsCanceled()) {
context->NoteOrphanedData();
if (orphaned && pinnedContext) {
if (pinnedContext->IsCanceled()) {
pinnedContext->NoteOrphanedData();
} else {
context->CancelForCacheId(aCacheId);
pinnedContext->CancelForCacheId(aCacheId);
RefPtr<Action> action =
new DeleteOrphanedCacheAction(SafeRefPtrFromThis(), aCacheId);
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
}
}
@ -1706,15 +1708,16 @@ void Manager::ReleaseBodyId(const nsID& aBodyId) {
if (mBodyIdRefs[i].mCount < 1) {
bool orphaned = mBodyIdRefs[i].mOrphaned;
mBodyIdRefs.RemoveElementAt(i);
RefPtr<Context> context = mContext;
const auto pinnedContext =
SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
// If the context is already gone, then orphan flag should have been
// set in RemoveContext().
if (orphaned && context) {
if (context->IsCanceled()) {
context->NoteOrphanedData();
if (orphaned && pinnedContext) {
if (pinnedContext->IsCanceled()) {
pinnedContext->NoteOrphanedData();
} else {
RefPtr<Action> action = new DeleteOrphanedBodyAction(aBodyId);
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
}
}
@ -1753,10 +1756,11 @@ void Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
return;
}
RefPtr<Context> context = mContext;
MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
MOZ_DIAGNOSTIC_ASSERT(!pinnedContext->IsCanceled());
RefPtr<StreamList> streamList = new StreamList(SafeRefPtrFromThis(), context);
RefPtr<StreamList> streamList =
new StreamList(SafeRefPtrFromThis(), pinnedContext.clonePtr());
ListenerId listenerId = SaveListener(aListener);
RefPtr<Action> action;
@ -1782,7 +1786,7 @@ void Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
MOZ_CRASH("Unknown Cache operation!");
}
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
void Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
@ -1795,10 +1799,11 @@ void Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
return;
}
RefPtr<Context> context = mContext;
MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
MOZ_DIAGNOSTIC_ASSERT(!pinnedContext->IsCanceled());
RefPtr<StreamList> streamList = new StreamList(SafeRefPtrFromThis(), context);
RefPtr<StreamList> streamList =
new StreamList(SafeRefPtrFromThis(), pinnedContext.clonePtr());
ListenerId listenerId = SaveListener(aListener);
RefPtr<Action> action;
@ -1829,7 +1834,7 @@ void Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
MOZ_CRASH("Unknown CacheStorage operation!");
}
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
void Manager::ExecuteOpenStream(Listener* aListener,
@ -1844,8 +1849,8 @@ void Manager::ExecuteOpenStream(Listener* aListener,
return;
}
RefPtr<Context> context = mContext;
MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
MOZ_DIAGNOSTIC_ASSERT(!pinnedContext->IsCanceled());
// We save the listener simply to track the existence of the caller here.
// Our returned value will really be passed to the resolver when the
@ -1856,7 +1861,7 @@ void Manager::ExecuteOpenStream(Listener* aListener,
RefPtr<Action> action = new OpenStreamAction(SafeRefPtrFromThis(), listenerId,
std::move(aResolver), aBodyId);
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
void Manager::ExecutePutAll(
@ -1872,8 +1877,8 @@ void Manager::ExecutePutAll(
return;
}
RefPtr<Context> context = mContext;
MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
MOZ_DIAGNOSTIC_ASSERT(!pinnedContext->IsCanceled());
ListenerId listenerId = SaveListener(aListener);
@ -1881,7 +1886,7 @@ void Manager::ExecutePutAll(
new CachePutAllAction(SafeRefPtrFromThis(), listenerId, aCacheId,
aPutList, aRequestStreamList, aResponseStreamList);
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread,
@ -1912,19 +1917,14 @@ Manager::~Manager() {
void Manager::Init(Maybe<Manager&> aOldManager) {
NS_ASSERT_OWNINGTHREAD(Manager);
RefPtr<Context> oldContext;
if (aOldManager) {
oldContext = aOldManager->mContext;
}
// Create the context immediately. Since there can at most be one Context
// per Manager now, this lets us cleanly call Factory::Remove() once the
// Context goes away.
RefPtr<Action> setupAction = new SetupAction();
RefPtr<Context> ref =
Context::Create(SafeRefPtrFromThis(), mIOThread->SerialEventTarget(),
setupAction, oldContext);
mContext = ref;
SafeRefPtr<Context> ref = Context::Create(
SafeRefPtrFromThis(), mIOThread->SerialEventTarget(), setupAction,
aOldManager ? SomeRef(*aOldManager->mContext) : Nothing());
mContext = ref.unsafeGetRawPtr();
}
void Manager::Shutdown() {
@ -1947,8 +1947,9 @@ void Manager::Shutdown() {
// If there is a context, then cancel and only note that we are done after
// its cleaned up.
if (mContext) {
RefPtr<Context> context = mContext;
context->CancelAll();
const auto pinnedContext =
SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
pinnedContext->CancelAll();
return;
}
}
@ -1963,8 +1964,8 @@ void Manager::Abort() {
NoteClosing();
// Cancel and only note that we are done after the context is cleaned up.
RefPtr<Context> context = mContext;
context->CancelAll();
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
pinnedContext->CancelAll();
}
Manager::ListenerId Manager::SaveListener(Listener* aListener) {
@ -2045,11 +2046,12 @@ void Manager::NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList) {
// TODO: note that we need to check these bodies for staleness on startup (bug
// 1110446)
RefPtr<Context> context = mContext;
if (!deleteNowList.IsEmpty() && context && !context->IsCanceled()) {
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
if (!deleteNowList.IsEmpty() && pinnedContext &&
!pinnedContext->IsCanceled()) {
RefPtr<Action> action =
new DeleteOrphanedBodyAction(std::move(deleteNowList));
context->Dispatch(action);
pinnedContext->Dispatch(action);
}
}
@ -2061,15 +2063,15 @@ void Manager::MaybeAllowContextToClose() {
// Cache state information to complete before doing this. Once we allow
// the Context to close we may not reliably get notified of storage
// invalidation.
RefPtr<Context> context = mContext;
if (context && mListeners.IsEmpty() && mCacheIdRefs.IsEmpty() &&
const auto pinnedContext = SafeRefPtr{mContext, AcquireStrongRefFromRawPtr{}};
if (pinnedContext && mListeners.IsEmpty() && mCacheIdRefs.IsEmpty() &&
mBodyIdRefs.IsEmpty()) {
// Mark this Manager as invalid so that it won't get used again. We don't
// want to start any new operations once we allow the Context to close since
// it may race with the underlying storage getting invalidated.
NoteClosing();
context->AllowToClose();
pinnedContext->AllowToClose();
}
}

2
dom/cache/Manager.h поставляемый
Просмотреть файл

@ -130,7 +130,7 @@ class Manager final : public SafeRefCounted<Manager> {
void RemoveListener(Listener* aListener);
// Must be called by Context objects before they are destroyed.
void RemoveContext(Context* aContext);
void RemoveContext(Context& aContext);
// Marks the Manager "invalid". Once the Context completes no new operations
// will be permitted with this Manager. New actors will get a new Manager.

5
dom/cache/StreamList.cpp поставляемый
Просмотреть файл

@ -15,9 +15,10 @@ namespace mozilla {
namespace dom {
namespace cache {
StreamList::StreamList(SafeRefPtr<Manager> aManager, Context* aContext)
StreamList::StreamList(SafeRefPtr<Manager> aManager,
SafeRefPtr<Context> aContext)
: mManager(std::move(aManager)),
mContext(aContext),
mContext(std::move(aContext)),
mCacheId(INVALID_CACHE_ID),
mStreamControl(nullptr),
mActivated(false) {

4
dom/cache/StreamList.h поставляемый
Просмотреть файл

@ -24,7 +24,7 @@ class Manager;
class StreamList final : public Context::Activity {
public:
StreamList(SafeRefPtr<Manager> aManager, Context* aContext);
StreamList(SafeRefPtr<Manager> aManager, SafeRefPtr<Context> aContext);
Manager& GetManager() const;
bool ShouldOpenStreamFor(const nsID& aId) const;
@ -56,7 +56,7 @@ class StreamList final : public Context::Activity {
nsCOMPtr<nsIInputStream> mStream;
};
SafeRefPtr<Manager> mManager;
RefPtr<Context> mContext;
SafeRefPtr<Context> mContext;
CacheId mCacheId;
CacheStreamControlParent* mStreamControl;
nsTArray<Entry> mList;