Skip to content

Commit

Permalink
Bug 1010717 - add nsIRunnable support to the DOM Storage thread. r=ma…
Browse files Browse the repository at this point in the history
…yhemer
  • Loading branch information
mak77 committed Jan 27, 2015
1 parent bf0386f commit 90300c0
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 19 deletions.
84 changes: 68 additions & 16 deletions dom/storage/DOMStorageDBThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ DOMStorageDBBridge::DOMStorageDBBridge()

DOMStorageDBThread::DOMStorageDBThread()
: mThread(nullptr)
, mMonitor("DOMStorageThreadMonitor")
, mThreadObserver(new ThreadObserver())
, mStopIOThread(false)
, mWALModeEnabled(false)
, mDBReady(false)
Expand Down Expand Up @@ -76,7 +76,7 @@ DOMStorageDBThread::Init()

// Need to keep the lock to avoid setting mThread later then
// the thread body executes.
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());

mThread = PR_CreateThread(PR_USER_THREAD, &DOMStorageDBThread::ThreadFunc, this,
PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,
Expand All @@ -98,7 +98,7 @@ DOMStorageDBThread::Shutdown()
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_SHUTDOWN_DATABASE_MS> timer;

{
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());

// After we stop, no other operations can be accepted
mFlushImmediately = true;
Expand Down Expand Up @@ -130,7 +130,7 @@ DOMStorageDBThread::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync)
if (mDBReady && mWALModeEnabled) {
bool pendingTasks;
{
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
pendingTasks = mPendingTasks.IsScopeUpdatePending(aCache->Scope()) ||
mPendingTasks.IsScopeClearPending(aCache->Scope());
}
Expand All @@ -157,15 +157,15 @@ DOMStorageDBThread::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync)
void
DOMStorageDBThread::AsyncFlush()
{
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
mFlushImmediately = true;
monitor.Notify();
}

bool
DOMStorageDBThread::ShouldPreloadScope(const nsACString& aScope)
{
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
return mScopesHavingData.Contains(aScope);
}

Expand All @@ -185,14 +185,14 @@ GetScopesHavingDataEnum(nsCStringHashKey* aKey, void* aArg)
void
DOMStorageDBThread::GetScopesHavingData(InfallibleTArray<nsCString>* aScopes)
{
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
mScopesHavingData.EnumerateEntries(GetScopesHavingDataEnum, aScopes);
}

nsresult
DOMStorageDBThread::InsertDBOp(DOMStorageDBThread::DBOperation* aOperation)
{
MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());

// Sentinel to don't forget to delete the operation when we exit early.
nsAutoPtr<DOMStorageDBThread::DBOperation> opScope(aOperation);
Expand All @@ -204,7 +204,7 @@ DOMStorageDBThread::InsertDBOp(DOMStorageDBThread::DBOperation* aOperation)
}

if (NS_FAILED(mStatus)) {
MonitorAutoUnlock unlock(mMonitor);
MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
aOperation->Finalize(mStatus);
return mStatus;
}
Expand All @@ -225,7 +225,7 @@ DOMStorageDBThread::InsertDBOp(DOMStorageDBThread::DBOperation* aOperation)
// actually been cleared from the database. Preloads are processed
// immediately before update and clear operations on the database that
// are flushed periodically in batches.
MonitorAutoUnlock unlock(mMonitor);
MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
aOperation->Finalize(NS_OK);
return NS_OK;
}
Expand Down Expand Up @@ -292,21 +292,40 @@ DOMStorageDBThread::ThreadFunc()
{
nsresult rv = InitDatabase();

MonitorAutoLock lockMonitor(mMonitor);
MonitorAutoLock lockMonitor(mThreadObserver->GetMonitor());

if (NS_FAILED(rv)) {
mStatus = rv;
mStopIOThread = true;
return;
}

while (MOZ_LIKELY(!mStopIOThread || mPreloads.Length() || mPendingTasks.HasTasks())) {
// Create an nsIThread for the current PRThread, so we can observe runnables
// dispatched to it.
nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
nsCOMPtr<nsIThreadInternal> threadInternal = do_QueryInterface(thread);
MOZ_ASSERT(threadInternal); // Should always succeed.
threadInternal->SetObserver(mThreadObserver);

while (MOZ_LIKELY(!mStopIOThread || mPreloads.Length() ||
mPendingTasks.HasTasks() ||
mThreadObserver->HasPendingEvents())) {
// Process xpcom events first.
while (MOZ_UNLIKELY(mThreadObserver->HasPendingEvents())) {
mThreadObserver->ClearPendingEvents();
MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
bool processedEvent;
do {
rv = thread->ProcessNextEvent(false, &processedEvent);
} while (NS_SUCCEEDED(rv) && processedEvent);
}

if (MOZ_UNLIKELY(TimeUntilFlush() == 0)) {
// Flush time is up or flush has been forced, do it now.
UnscheduleFlush();
if (mPendingTasks.Prepare()) {
{
MonitorAutoUnlock unlockMonitor(mMonitor);
MonitorAutoUnlock unlockMonitor(mThreadObserver->GetMonitor());
rv = mPendingTasks.Execute(this);
}

Expand All @@ -320,7 +339,7 @@ DOMStorageDBThread::ThreadFunc()
nsAutoPtr<DBOperation> op(mPreloads[0]);
mPreloads.RemoveElementAt(0);
{
MonitorAutoUnlock unlockMonitor(mMonitor);
MonitorAutoUnlock unlockMonitor(mThreadObserver->GetMonitor());
op->PerformAndFinalize(this);
}

Expand All @@ -333,8 +352,41 @@ DOMStorageDBThread::ThreadFunc()
} // thread loop

mStatus = ShutdownDatabase();

if (threadInternal) {
threadInternal->SetObserver(nullptr);
}
}


NS_IMPL_ISUPPORTS(DOMStorageDBThread::ThreadObserver, nsIThreadObserver)

NS_IMETHODIMP
DOMStorageDBThread::ThreadObserver::OnDispatchedEvent(nsIThreadInternal *thread)
{
MonitorAutoLock lock(mMonitor);
mHasPendingEvents = true;
lock.Notify();
return NS_OK;
}

NS_IMETHODIMP
DOMStorageDBThread::ThreadObserver::OnProcessNextEvent(nsIThreadInternal *thread,
bool mayWait,
uint32_t recursionDepth)
{
return NS_OK;
}

NS_IMETHODIMP
DOMStorageDBThread::ThreadObserver::AfterProcessNextEvent(nsIThreadInternal *thread,
uint32_t recursionDepth,
bool eventWasProcessed)
{
return NS_OK;
}


extern void
ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult);

Expand Down Expand Up @@ -508,7 +560,7 @@ DOMStorageDBThread::InitDatabase()
rv = stmt->GetUTF8String(0, foundScope);
NS_ENSURE_SUCCESS(rv, rv);

MonitorAutoLock monitor(mMonitor);
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
mScopesHavingData.PutEntry(foundScope);
}

Expand Down Expand Up @@ -648,7 +700,7 @@ DOMStorageDBThread::ScheduleFlush()
mDirtyEpoch = PR_IntervalNow() | 1; // Must be non-zero to indicate we are scheduled

// Wake the monitor from indefinite sleep...
mMonitor.Notify();
(mThreadObserver->GetMonitor()).Notify();
}

void
Expand Down
36 changes: 33 additions & 3 deletions dom/storage/DOMStorageDBThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsClassHashtable.h"
#include "nsIFile.h"
#include "nsIThreadInternal.h"

class mozIStorageConnection;

Expand Down Expand Up @@ -208,6 +209,34 @@ class DOMStorageDBThread MOZ_FINAL : public DOMStorageDBBridge
uint32_t mFlushFailureCount;
};

class ThreadObserver MOZ_FINAL : public nsIThreadObserver
{
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSITHREADOBSERVER

ThreadObserver()
: mHasPendingEvents(false)
, mMonitor("DOMStorageThreadMonitor")
{
}

bool HasPendingEvents() {
mMonitor.AssertCurrentThreadOwns();
return mHasPendingEvents;
}
void ClearPendingEvents() {
mMonitor.AssertCurrentThreadOwns();
mHasPendingEvents = false;
}
Monitor& GetMonitor() { return mMonitor; }

private:
virtual ~ThreadObserver() {}
bool mHasPendingEvents;
// The monitor we drive the thread with
Monitor mMonitor;
};

public:
DOMStorageDBThread();
virtual ~DOMStorageDBThread() {}
Expand Down Expand Up @@ -250,10 +279,11 @@ class DOMStorageDBThread MOZ_FINAL : public DOMStorageDBBridge
nsCOMPtr<nsIFile> mDatabaseFile;
PRThread* mThread;

// The monitor we drive the thread with
Monitor mMonitor;
// Used to observe runnables dispatched to our thread and to monitor it.
nsRefPtr<ThreadObserver> mThreadObserver;

// Flag to stop, protected by the monitor
// Flag to stop, protected by the monitor returned by
// mThreadObserver->GetMonitor().
bool mStopIOThread;

// Whether WAL is enabled
Expand Down

0 comments on commit 90300c0

Please sign in to comment.