Bug 1526891 - Part 18: Remove main thread use from StorageOperationBase; r=asuth

Differential Revision: https://phabricator.services.mozilla.com/D20927
This commit is contained in:
Jan Varga 2019-02-23 17:41:23 +01:00
Родитель 93fc3f1b66
Коммит 977e7c62d6
1 изменённых файлов: 171 добавлений и 105 удалений

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

@ -1152,6 +1152,10 @@ class PersistOp final : public PersistRequestBase {
void GetResponse(RequestResponse& aResponse) override; void GetResponse(RequestResponse& aResponse) override;
}; };
/*******************************************************************************
* Other class declarations
******************************************************************************/
class StoragePressureRunnable final : public Runnable { class StoragePressureRunnable final : public Runnable {
const uint64_t mUsage; const uint64_t mUsage;
@ -1166,6 +1170,31 @@ class StoragePressureRunnable final : public Runnable {
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
}; };
/*******************************************************************************
* Helper classes
******************************************************************************/
class PrincipalVerifier final : public Runnable {
nsTArray<PrincipalInfo> mPrincipalInfos;
public:
static already_AddRefed<PrincipalVerifier> CreateAndDispatch(
nsTArray<PrincipalInfo>&& aPrincipalInfos);
private:
explicit PrincipalVerifier(nsTArray<PrincipalInfo>&& aPrincipalInfos)
: Runnable("dom::quota::PrincipalVerifier"),
mPrincipalInfos(std::move(aPrincipalInfos)) {
AssertIsOnIOThread();
}
virtual ~PrincipalVerifier() = default;
bool IsPrincipalInfoValid(const PrincipalInfo& aPrincipalInfo);
NS_DECL_NSIRUNNABLE
};
/******************************************************************************* /*******************************************************************************
* Helper Functions * Helper Functions
******************************************************************************/ ******************************************************************************/
@ -1303,12 +1332,7 @@ Atomic<uint32_t, Relaxed> gChunkSizeKB(kDefaultChunkSizeKB);
Atomic<bool> gTestingEnabled(false); Atomic<bool> gTestingEnabled(false);
class StorageOperationBase : public Runnable { class StorageOperationBase {
mozilla::Mutex mMutex;
mozilla::CondVar mCondVar;
nsresult mMainThreadResultCode;
bool mWaiting;
protected: protected:
struct OriginProps; struct OriginProps;
@ -1320,16 +1344,12 @@ class StorageOperationBase : public Runnable {
public: public:
StorageOperationBase(nsIFile* aDirectory, bool aPersistent) StorageOperationBase(nsIFile* aDirectory, bool aPersistent)
: Runnable("dom::quota::StorageOperationBase"), : mDirectory(aDirectory), mPersistent(aPersistent) {
mMutex("StorageOperationBase::mMutex"),
mCondVar(mMutex, "StorageOperationBase::mCondVar"),
mMainThreadResultCode(NS_OK),
mWaiting(true),
mDirectory(aDirectory),
mPersistent(aPersistent) {
AssertIsOnIOThread(); AssertIsOnIOThread();
} }
NS_INLINE_DECL_REFCOUNTING(StorageOperationBase)
protected: protected:
virtual ~StorageOperationBase() {} virtual ~StorageOperationBase() {}
@ -1352,12 +1372,6 @@ class StorageOperationBase : public Runnable {
nsresult ProcessOriginDirectories(); nsresult ProcessOriginDirectories();
virtual nsresult ProcessOriginDirectory(const OriginProps& aOriginProps) = 0; virtual nsresult ProcessOriginDirectory(const OriginProps& aOriginProps) = 0;
private:
nsresult RunOnMainThread();
NS_IMETHOD
Run() override;
}; };
struct StorageOperationBase::OriginProps { struct StorageOperationBase::OriginProps {
@ -7731,6 +7745,90 @@ void PersistOp::GetResponse(RequestResponse& aResponse) {
aResponse = PersistResponse(); aResponse = PersistResponse();
} }
// static
already_AddRefed<PrincipalVerifier> PrincipalVerifier::CreateAndDispatch(
nsTArray<PrincipalInfo>&& aPrincipalInfos) {
AssertIsOnIOThread();
RefPtr<PrincipalVerifier> verifier =
new PrincipalVerifier(std::move(aPrincipalInfos));
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(verifier));
return verifier.forget();
}
bool PrincipalVerifier::IsPrincipalInfoValid(
const PrincipalInfo& aPrincipalInfo) {
MOZ_ASSERT(NS_IsMainThread());
switch (aPrincipalInfo.type()) {
// A system principal is acceptable.
case PrincipalInfo::TSystemPrincipalInfo: {
return true;
}
case PrincipalInfo::TContentPrincipalInfo: {
const ContentPrincipalInfo& info =
aPrincipalInfo.get_ContentPrincipalInfo();
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), info.spec());
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(uri, info.attrs());
if (NS_WARN_IF(!principal)) {
return false;
}
nsCString originNoSuffix;
rv = principal->GetOriginNoSuffix(originNoSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (NS_WARN_IF(originNoSuffix != info.originNoSuffix())) {
QM_WARNING("originNoSuffix (%s) doesn't match passed one (%s)!",
originNoSuffix.get(), info.originNoSuffix().get());
return false;
}
nsCString baseDomain;
rv = principal->GetBaseDomain(baseDomain);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (NS_WARN_IF(baseDomain != info.baseDomain())) {
QM_WARNING("baseDomain (%s) doesn't match passed one (%s)!",
baseDomain.get(), info.baseDomain().get());
return false;
}
return true;
}
default: { break; }
}
// Null and expanded principals are not acceptable.
return false;
}
NS_IMETHODIMP
PrincipalVerifier::Run() {
MOZ_ASSERT(NS_IsMainThread());
for (auto& principalInfo : mPrincipalInfos) {
MOZ_DIAGNOSTIC_ASSERT(IsPrincipalInfoValid(principalInfo));
}
return NS_OK;
}
nsresult StorageOperationBase::GetDirectoryMetadata(nsIFile* aDirectory, nsresult StorageOperationBase::GetDirectoryMetadata(nsIFile* aDirectory,
int64_t& aTimestamp, int64_t& aTimestamp,
nsACString& aGroup, nsACString& aGroup,
@ -7870,27 +7968,66 @@ nsresult StorageOperationBase::ProcessOriginDirectories() {
AssertIsOnIOThread(); AssertIsOnIOThread();
MOZ_ASSERT(!mOriginProps.IsEmpty()); MOZ_ASSERT(!mOriginProps.IsEmpty());
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this)); nsresult rv;
{ nsTArray<PrincipalInfo> principalInfos;
mozilla::MutexAutoLock autolock(mMutex);
while (mWaiting) { for (auto& originProps : mOriginProps) {
mCondVar.Wait(); switch (originProps.mType) {
case OriginProps::eChrome: {
QuotaManager::GetInfoForChrome(
&originProps.mSuffix, &originProps.mGroup, &originProps.mOrigin);
break;
}
case OriginProps::eContent: {
RefPtr<MozURL> specURL;
nsresult rv = MozURL::Init(getter_AddRefs(specURL), originProps.mSpec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCString originNoSuffix;
specURL->Origin(originNoSuffix);
nsCString baseDomain;
rv = specURL->BaseDomain(baseDomain);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
ContentPrincipalInfo contentPrincipalInfo;
contentPrincipalInfo.attrs() = originProps.mAttrs;
contentPrincipalInfo.originNoSuffix() = originNoSuffix;
contentPrincipalInfo.spec() = originProps.mSpec;
contentPrincipalInfo.baseDomain() = baseDomain;
PrincipalInfo principalInfo(contentPrincipalInfo);
QuotaManager::GetInfoFromValidatedPrincipalInfo(
principalInfo, &originProps.mSuffix, &originProps.mGroup,
&originProps.mOrigin);
principalInfos.AppendElement(principalInfo);
break;
}
case OriginProps::eObsolete: {
// There's no way to get info for obsolete origins.
break;
}
default:
MOZ_CRASH("Bad type!");
} }
} }
if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) { if (!principalInfos.IsEmpty()) {
return mMainThreadResultCode; RefPtr<PrincipalVerifier> principalVerifier =
PrincipalVerifier::CreateAndDispatch(std::move(principalInfos));
} }
// Verify that the bounce to the main thread didn't start the shutdown
// sequence.
if (NS_WARN_IF(QuotaManager::IsShuttingDown())) {
return NS_ERROR_FAILURE;
}
nsresult rv;
// Don't try to upgrade obsolete origins, remove them right after we detect // Don't try to upgrade obsolete origins, remove them right after we detect
// them. // them.
for (auto& originProps : mOriginProps) { for (auto& originProps : mOriginProps) {
@ -7914,77 +8051,6 @@ nsresult StorageOperationBase::ProcessOriginDirectories() {
return NS_OK; return NS_OK;
} }
nsresult StorageOperationBase::RunOnMainThread() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mOriginProps.IsEmpty());
nsresult rv;
for (uint32_t count = mOriginProps.Length(), index = 0; index < count;
index++) {
OriginProps& originProps = mOriginProps[index];
switch (originProps.mType) {
case OriginProps::eChrome: {
QuotaManager::GetInfoForChrome(
&originProps.mSuffix, &originProps.mGroup, &originProps.mOrigin);
break;
}
case OriginProps::eContent: {
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), originProps.mSpec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(uri, originProps.mAttrs);
if (NS_WARN_IF(!principal)) {
return NS_ERROR_FAILURE;
}
rv = QuotaManager::GetInfoFromPrincipal(principal, &originProps.mSuffix,
&originProps.mGroup,
&originProps.mOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
break;
}
case OriginProps::eObsolete: {
// There's no way to get info for obsolete origins.
break;
}
default:
MOZ_CRASH("Bad type!");
}
}
return NS_OK;
}
NS_IMETHODIMP
StorageOperationBase::Run() {
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = RunOnMainThread();
if (NS_WARN_IF(NS_FAILED(rv))) {
mMainThreadResultCode = rv;
}
MutexAutoLock lock(mMutex);
MOZ_ASSERT(mWaiting);
mWaiting = false;
mCondVar.Notify();
return NS_OK;
}
nsresult StorageOperationBase::OriginProps::Init(nsIFile* aDirectory) { nsresult StorageOperationBase::OriginProps::Init(nsIFile* aDirectory) {
AssertIsOnIOThread(); AssertIsOnIOThread();
MOZ_ASSERT(aDirectory); MOZ_ASSERT(aDirectory);