Index: Source/core/workers/WorkerThreadTest.cpp |
diff --git a/Source/core/workers/WorkerThreadTest.cpp b/Source/core/workers/WorkerThreadTest.cpp |
index 5f9270a37db506064d5faf65a6e05adbe42f0fea..bf88997d26d2727d4dc6627a15632c17f5b3e738 100644 |
--- a/Source/core/workers/WorkerThreadTest.cpp |
+++ b/Source/core/workers/WorkerThreadTest.cpp |
@@ -9,6 +9,7 @@ |
#include "core/workers/WorkerReportingProxy.h" |
#include "core/workers/WorkerThreadStartupData.h" |
#include "platform/NotImplemented.h" |
+#include "public/platform/WebScheduler.h" |
#include "public/platform/WebWaitableEvent.h" |
#include <gmock/gmock.h> |
#include <gtest/gtest.h> |
@@ -97,6 +98,8 @@ public: |
return *m_thread; |
} |
+ MOCK_METHOD1(doIdleGc, bool(double deadlineSeconds)); |
+ |
PassRefPtrWillBeRawPtr<WorkerGlobalScope> createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData> startupData) override |
{ |
return adoptRefWillBeNoop(new FakeWorkerGlobalScope(startupData->m_scriptURL, startupData->m_userAgent, this, startupData->m_starterOrigin, startupData->m_workerClients.release())); |
@@ -106,6 +109,30 @@ private: |
OwnPtr<WebThreadSupportingGC> m_thread; |
}; |
+class WakeupTask : public WebThread::Task { |
+public: |
+ WakeupTask() { } |
+ |
+ ~WakeupTask() override { } |
+ |
+ void run() override { } |
+}; |
+ |
+class PostDelayedWakeupTask : public WebThread::Task { |
+public: |
+ PostDelayedWakeupTask(WebScheduler* scheduler, long long delay) : m_scheduler(scheduler), m_delay(delay) { } |
+ |
+ ~PostDelayedWakeupTask() override { } |
+ |
+ void run() override |
+ { |
+ m_scheduler->postTimerTask(FROM_HERE, new WakeupTask(), m_delay); |
+ } |
+ |
+ WebScheduler* m_scheduler; // Not owned. |
+ long long m_delay; |
+}; |
+ |
class SignalTask : public WebThread::Task { |
public: |
SignalTask(WebWaitableEvent* completionEvent) : m_completionEvent(completionEvent) { } |
@@ -161,6 +188,17 @@ public: |
completionEvent->wait(); |
} |
+ void postWakeUpTask(long long waitMs) |
+ { |
+ WebScheduler* scheduler = m_workerThread->backingThread().platformThread().scheduler(); |
+ |
+ // The idle task will get posted on an after wake up queue, so we need another task |
+ // posted at the right time to wake the system up. We don't know the right delay here |
+ // since the thread can take a variable length of time to be responsive, however this |
+ // isn't a problem when posting a delayed task from within a task on the worker thread. |
+ scheduler->postLoadingTask(FROM_HERE, new PostDelayedWakeupTask(scheduler, waitMs)); |
+ } |
+ |
protected: |
void ExpectWorkerLifetimeReportingCalls() |
{ |
@@ -182,4 +220,76 @@ TEST_F(WorkerThreadTest, StartAndStop) |
m_workerThread->terminateAndWait(); |
} |
+TEST_F(WorkerThreadTest, GcOccursWhileIdle) |
+{ |
+ OwnPtr<WebWaitableEvent> gcDone = adoptPtr(Platform::current()->createWaitableEvent()); |
+ |
+ ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke( |
+ [&gcDone](double) |
+ { |
+ gcDone->signal(); |
+ return false; |
+ })); |
+ |
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1); |
+ |
+ startAndWaitForInit(); |
+ postWakeUpTask(500ul); |
+ |
+ gcDone->wait(); |
+ m_workerThread->terminateAndWait(); |
+}; |
+ |
+class RepeatingTask : public WebThread::Task { |
+public: |
+ RepeatingTask(WebScheduler* scheduler, WebWaitableEvent* completion) |
+ : RepeatingTask(scheduler, completion, 0) { } |
+ |
+ ~RepeatingTask() override { } |
+ |
+ void run() override |
+ { |
+ m_taskCount++; |
+ if (m_taskCount == 10) |
+ m_completion->signal(); |
+ |
+ m_scheduler->postTimerTask( |
+ FROM_HERE, new RepeatingTask(m_scheduler, m_completion, m_taskCount), 0ul); |
+ m_scheduler->postLoadingTask(FROM_HERE, new WakeupTask()); |
+ |
+ } |
+ |
+private: |
+ RepeatingTask(WebScheduler* scheduler, WebWaitableEvent* completion, int taskCount) |
+ : m_scheduler(scheduler) |
+ , m_completion(completion) |
+ , m_taskCount(taskCount) |
+ { } |
+ |
+ WebScheduler* m_scheduler; // Not owned. |
+ WebWaitableEvent* m_completion; |
+ int m_taskCount; |
+}; |
+ |
+TEST_F(WorkerThreadTest, GcDoesNotOccurWhenNotIdle) |
+{ |
+ OwnPtr<WebWaitableEvent> completion = adoptPtr(Platform::current()->createWaitableEvent()); |
+ |
+ EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(0); |
+ |
+ startAndWaitForInit(); |
+ |
+ WebScheduler* scheduler = m_workerThread->backingThread().platformThread().scheduler(); |
+ |
+ // Post a repeating task that should prevent any GC from happening. |
+ scheduler->postLoadingTask(FROM_HERE, new RepeatingTask(scheduler, completion.get())); |
+ |
+ completion->wait(); |
+ |
+ // Make sure doIdleGc has not been called by this stage. |
+ Mock::VerifyAndClearExpectations(m_workerThread.get()); |
+ |
+ m_workerThread->terminateAndWait(); |
+} |
+ |
} // namespace blink |