diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-02-09 08:11:38 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-02-09 08:51:28 +0100 |
commit | 8cd777888a40e987ad536ab68421068f5c06d83b (patch) | |
tree | d046b56471878f2531f4c741db076f1622e3365f /dom/asmjscache/AsmJSCache.cpp | |
parent | a1a0b03046f68f4b0a22b9ec3086942551fbf469 (diff) | |
download | UXP-8cd777888a40e987ad536ab68421068f5c06d83b.tar UXP-8cd777888a40e987ad536ab68421068f5c06d83b.tar.gz UXP-8cd777888a40e987ad536ab68421068f5c06d83b.tar.lz UXP-8cd777888a40e987ad536ab68421068f5c06d83b.tar.xz UXP-8cd777888a40e987ad536ab68421068f5c06d83b.zip |
Fix a rare crash with asm.js caching.
Diffstat (limited to 'dom/asmjscache/AsmJSCache.cpp')
-rw-r--r-- | dom/asmjscache/AsmJSCache.cpp | 336 |
1 files changed, 241 insertions, 95 deletions
diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index 4e1912f23..be54987a1 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -69,6 +69,8 @@ namespace asmjscache { namespace { +class ParentRunnable; + // Anything smaller should compile fast enough that caching will just add // overhead. static const size_t sMinCachedModuleLength = 10000; @@ -76,6 +78,10 @@ static const size_t sMinCachedModuleLength = 10000; // The number of characters to hash into the Metadata::Entry::mFastHash. static const unsigned sNumFastHashChars = 4096; +// Track all live parent actors. +typedef nsTArray<const ParentRunnable*> ParentActorArray; +StaticAutoPtr<ParentActorArray> sLiveParentActors; + nsresult WriteMetadataFile(nsIFile* aMetadataFile, const Metadata& aMetadata) { @@ -236,6 +242,94 @@ EvictEntries(nsIFile* aDirectory, const nsACString& aGroup, } } +/******************************************************************************* + * Client + ******************************************************************************/ + +class Client + : public quota::Client +{ + static Client* sInstance; + + bool mShutdownRequested; + +public: + Client(); + + static bool + IsShuttingDownOnBackgroundThread() + { + AssertIsOnBackgroundThread(); + + if (sInstance) { + return sInstance->IsShuttingDown(); + } + + return QuotaManager::IsShuttingDown(); + } + + static bool + IsShuttingDownOnNonBackgroundThread() + { + MOZ_ASSERT(!IsOnBackgroundThread()); + + return QuotaManager::IsShuttingDown(); + } + + bool + IsShuttingDown() const + { + AssertIsOnBackgroundThread(); + + return mShutdownRequested; + } + + NS_INLINE_DECL_REFCOUNTING(Client, override) + + virtual Type + GetType() override; + + virtual nsresult + InitOrigin(PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + const AtomicBool& aCanceled, + UsageInfo* aUsageInfo) override; + + virtual nsresult + GetUsageForOrigin(PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + const AtomicBool& aCanceled, + UsageInfo* aUsageInfo) override; + + virtual void + OnOriginClearCompleted(PersistenceType aPersistenceType, + const nsACString& aOrigin) + override; + + virtual void + ReleaseIOThreadObjects() override; + + virtual void + AbortOperations(const nsACString& aOrigin) override; + + virtual void + AbortOperationsForProcess(ContentParentId aContentParentId) override; + + virtual void + StartIdleMaintenance() override; + + virtual void + StopIdleMaintenance() override; + + virtual void + ShutdownWorkThreads() override; + +private: + ~Client(); +}; + // FileDescriptorHolder owns a file descriptor and its memory mapping. // FileDescriptorHolder is derived by two runnable classes (that is, // (Parent|Child)Runnable. @@ -897,6 +991,13 @@ ParentRunnable::FinishOnOwningThread() FileDescriptorHolder::Finish(); mDirectoryLock = nullptr; + + MOZ_ASSERT(sLiveParentActors); + sLiveParentActors->RemoveElement(this); + + if (sLiveParentActors->IsEmpty()) { + sLiveParentActors = nullptr; + } } NS_IMETHODIMP @@ -1140,6 +1241,10 @@ AllocEntryParent(OpenMode aOpenMode, { AssertIsOnBackgroundThread(); + if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread())) { + return nullptr; + } + if (NS_WARN_IF(aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo)) { MOZ_ASSERT(false); return nullptr; @@ -1148,6 +1253,12 @@ AllocEntryParent(OpenMode aOpenMode, RefPtr<ParentRunnable> runnable = new ParentRunnable(aPrincipalInfo, aOpenMode, aWriteParams); + if (!sLiveParentActors) { + sLiveParentActors = new ParentActorArray(); + } + + sLiveParentActors->AppendElement(runnable); + nsresult rv = NS_DispatchToMainThread(runnable); NS_ENSURE_SUCCESS(rv, nullptr); @@ -1712,128 +1823,163 @@ CloseEntryForWrite(size_t aSize, } } -class Client : public quota::Client +/******************************************************************************* + * Client + ******************************************************************************/ + +Client* Client::sInstance = nullptr; + +Client::Client() + : mShutdownRequested(false) { - ~Client() {} + AssertIsOnBackgroundThread(); + MOZ_ASSERT(!sInstance, "We expect this to be a singleton!"); -public: - NS_IMETHOD_(MozExternalRefCountType) - AddRef() override; + sInstance = this; +} - NS_IMETHOD_(MozExternalRefCountType) - Release() override; +Client::~Client() +{ + AssertIsOnBackgroundThread(); + MOZ_ASSERT(sInstance == this, "We expect this to be a singleton!"); - virtual Type - GetType() override - { - return ASMJS; - } + sInstance = nullptr; +} - virtual nsresult - InitOrigin(PersistenceType aPersistenceType, - const nsACString& aGroup, - const nsACString& aOrigin, - const AtomicBool& aCanceled, - UsageInfo* aUsageInfo) override - { - if (!aUsageInfo) { - return NS_OK; - } - return GetUsageForOrigin(aPersistenceType, - aGroup, - aOrigin, - aCanceled, - aUsageInfo); - } +Client::Type +Client::GetType() +{ + return ASMJS; +} - virtual nsresult - GetUsageForOrigin(PersistenceType aPersistenceType, - const nsACString& aGroup, - const nsACString& aOrigin, - const AtomicBool& aCanceled, - UsageInfo* aUsageInfo) override - { - QuotaManager* qm = QuotaManager::Get(); - MOZ_ASSERT(qm, "We were being called by the QuotaManager"); +nsresult +Client::InitOrigin(PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + const AtomicBool& aCanceled, + UsageInfo* aUsageInfo) +{ + if (!aUsageInfo) { + return NS_OK; + } + return GetUsageForOrigin(aPersistenceType, + aGroup, + aOrigin, + aCanceled, + aUsageInfo); +} - nsCOMPtr<nsIFile> directory; - nsresult rv = qm->GetDirectoryForOrigin(aPersistenceType, aOrigin, - getter_AddRefs(directory)); - NS_ENSURE_SUCCESS(rv, rv); - MOZ_ASSERT(directory, "We're here because the origin directory exists"); +nsresult +Client::GetUsageForOrigin(PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + const AtomicBool& aCanceled, + UsageInfo* aUsageInfo) +{ + QuotaManager* qm = QuotaManager::Get(); + MOZ_ASSERT(qm, "We were being called by the QuotaManager"); - rv = directory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIFile> directory; + nsresult rv = qm->GetDirectoryForOrigin(aPersistenceType, aOrigin, + getter_AddRefs(directory)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - DebugOnly<bool> exists; - MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists); + MOZ_ASSERT(directory, "We're here because the origin directory exists"); - nsCOMPtr<nsISimpleEnumerator> entries; - rv = directory->GetDirectoryEntries(getter_AddRefs(entries)); - NS_ENSURE_SUCCESS(rv, rv); + rv = directory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - bool hasMore; - while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && - hasMore && !aCanceled) { - nsCOMPtr<nsISupports> entry; - rv = entries->GetNext(getter_AddRefs(entry)); - NS_ENSURE_SUCCESS(rv, rv); + DebugOnly<bool> exists; + MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists); - nsCOMPtr<nsIFile> file = do_QueryInterface(entry); - NS_ENSURE_TRUE(file, NS_NOINTERFACE); + nsCOMPtr<nsISimpleEnumerator> entries; + rv = directory->GetDirectoryEntries(getter_AddRefs(entries)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - int64_t fileSize; - rv = file->GetFileSize(&fileSize); - NS_ENSURE_SUCCESS(rv, rv); + bool hasMore; + while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && + hasMore && !aCanceled) { + nsCOMPtr<nsISupports> entry; + rv = entries->GetNext(getter_AddRefs(entry)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - MOZ_ASSERT(fileSize >= 0, "Negative size?!"); + nsCOMPtr<nsIFile> file = do_QueryInterface(entry); + if (NS_WARN_IF(!file)) { + return NS_NOINTERFACE; + } - // Since the client is not explicitly storing files, append to database - // usage which represents implicit storage allocation. - aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize)); + int64_t fileSize; + rv = file->GetFileSize(&fileSize); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; + MOZ_ASSERT(fileSize >= 0, "Negative size?!"); + + // Since the client is not explicitly storing files, append to database + // usage which represents implicit storage allocation. + aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize)); + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } - virtual void - OnOriginClearCompleted(PersistenceType aPersistenceType, - const nsACString& aOrigin) - override - { } + return NS_OK; +} - virtual void - ReleaseIOThreadObjects() override - { } +void +Client::OnOriginClearCompleted(PersistenceType aPersistenceType, + const nsACString& aOrigin) +{ +} - virtual void - AbortOperations(const nsACString& aOrigin) override - { } +void +Client::ReleaseIOThreadObjects() +{ +} - virtual void - AbortOperationsForProcess(ContentParentId aContentParentId) override - { } +void +Client::AbortOperations(const nsACString& aOrigin) +{ +} - virtual void - StartIdleMaintenance() override - { } +void +Client::AbortOperationsForProcess(ContentParentId aContentParentId) +{ +} - virtual void - StopIdleMaintenance() override - { } +void +Client::StartIdleMaintenance() +{ +} - virtual void - ShutdownWorkThreads() override - { } +void +Client::StopIdleMaintenance() +{ +} -private: - nsAutoRefCnt mRefCnt; - NS_DECL_OWNINGTHREAD -}; +void +Client::ShutdownWorkThreads() +{ + AssertIsOnBackgroundThread(); + + if (sLiveParentActors) { + nsIThread* currentThread = NS_GetCurrentThread(); + MOZ_ASSERT(currentThread); -NS_IMPL_ADDREF(asmjscache::Client) -NS_IMPL_RELEASE(asmjscache::Client) + do { + MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(currentThread)); + } while (!sLiveParentActors); + } +} quota::Client* CreateClient() |