 Chromium Code Reviews
 Chromium Code Reviews Issue 507873003:
  [Blink-Worker] WorkerThread fires idleHandler only at the end of processing all tasks.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master
    
  
    Issue 507873003:
  [Blink-Worker] WorkerThread fires idleHandler only at the end of processing all tasks.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master| Index: Source/core/workers/WorkerThread.cpp | 
| diff --git a/Source/core/workers/WorkerThread.cpp b/Source/core/workers/WorkerThread.cpp | 
| index 8832399a59bd08bf883af07249593c1d2ea2534f..6819793790d71efbfa2a69a30d9f7994bed03421 100644 | 
| --- a/Source/core/workers/WorkerThread.cpp | 
| +++ b/Source/core/workers/WorkerThread.cpp | 
| @@ -45,7 +45,7 @@ | 
| #include "public/platform/WebThread.h" | 
| #include "public/platform/WebWaitableEvent.h" | 
| #include "public/platform/WebWorkerRunLoop.h" | 
| -#include "wtf/Noncopyable.h" | 
| +#include "wtf/Atomics.h" | 
| #include "wtf/text/WTFString.h" | 
| #include <utility> | 
| @@ -178,48 +178,50 @@ private: | 
| WorkerThreadCancelableTask* m_lastQueuedTask; | 
| }; | 
| -class WorkerThreadTask : public blink::WebThread::Task { | 
| - WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED; | 
| -public: | 
| - static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask> task, bool isInstrumented) | 
| - { | 
| - return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented)); | 
| - } | 
| +// WorkerThreadTask made private to WorkerThread | 
| - virtual ~WorkerThreadTask() { } | 
| +PassOwnPtr<WorkerThread::WorkerThreadTask> WorkerThread::WorkerThreadTask::create(WorkerThread& workerThread | 
| + , PassOwnPtr<ExecutionContextTask> task, bool isInstrumented) | 
| +{ | 
| + return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented)); | 
| +} | 
| - virtual void run() OVERRIDE | 
| - { | 
| - WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope(); | 
| - // Tasks could be put on the message loop after the cleanup task, | 
| - // ensure none of those are ran. | 
| - if (!workerGlobalScope) | 
| - return; | 
| +void WorkerThread::WorkerThreadTask::run() | 
| +{ | 
| + WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope(); | 
| + // Tasks could be put on the message loop after the cleanup task, | 
| + // ensure none of those are ran. | 
| + if (!workerGlobalScope) | 
| + return; | 
| - if (m_isInstrumented) | 
| - InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalScope, m_task.get()); | 
| - if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask()) | 
| + if (m_isInstrumented) | 
| + InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalScope, m_task.get()); | 
| + if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask()) | 
| + if (!m_isIdleHandlerTask || (m_isIdleHandlerTask && !m_workerThread.taskCount())) { | 
| m_task->performTask(workerGlobalScope); | 
| - if (m_isInstrumented) | 
| - InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalScope); | 
| - } | 
| - | 
| -private: | 
| - WorkerThreadTask(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask> task, bool isInstrumented) | 
| - : m_workerThread(workerThread) | 
| - , m_task(task) | 
| - , m_isInstrumented(isInstrumented) | 
| - { | 
| - if (m_isInstrumented) | 
| - m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty(); | 
| - if (m_isInstrumented) | 
| - InspectorInstrumentation::didPostExecutionContextTask(m_workerThread.workerGlobalScope(), m_task.get()); | 
| - } | 
| + } | 
| + if (m_isInstrumented) | 
| + InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalScope); | 
| + | 
| + // If no more tasks are queued up after this, then queue up the idleHandler | 
| + // to trigger GC. | 
| + if (!m_isIdleHandlerTask && !m_workerThread.decrementAndReturnTaskCount() | 
| + && !m_workerThread.m_IdleHandlerTaskPosted) | 
| 
jochen (gone - plz use gerrit)
2014/10/14 13:46:03
nit. put on previous line
 | 
| + m_workerThread.queueUpIdleHandlerNow(kLongIdleHandlerDelayMs); | 
| +} | 
| - WorkerThread& m_workerThread; | 
| - OwnPtr<ExecutionContextTask> m_task; | 
| - bool m_isInstrumented; | 
| -}; | 
| +WorkerThread::WorkerThreadTask::WorkerThreadTask(WorkerThread& workerThread | 
| + , PassOwnPtr<ExecutionContextTask> task, bool isInstrumented) | 
| + : m_workerThread(workerThread) | 
| + , m_task(task) | 
| + , m_isInstrumented(isInstrumented) | 
| + , m_isIdleHandlerTask(false) | 
| +{ | 
| + if (m_isInstrumented) | 
| + m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty(); | 
| + if (m_isInstrumented) | 
| + InspectorInstrumentation::didPostExecutionContextTask(m_workerThread.workerGlobalScope(), m_task.get()); | 
| +} | 
| class RunDebuggerQueueTask FINAL : public ExecutionContextTask { | 
| public: | 
| @@ -246,6 +248,8 @@ WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReporting | 
| , m_startupData(startupData) | 
| , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent())) | 
| , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEvent())) | 
| + , m_IdleHandlerTaskPosted(false) | 
| + , m_tasksCount(0) | 
| { | 
| MutexLocker lock(threadSetMutex()); | 
| workerThreads().add(this); | 
| @@ -321,8 +325,6 @@ void WorkerThread::initialize() | 
| script->evaluate(ScriptSourceCode(sourceCode, scriptURL)); | 
| postInitialize(); | 
| - | 
| - postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), kShortIdleHandlerDelayMs); | 
| } | 
| void WorkerThread::cleanup() | 
| @@ -459,29 +461,58 @@ bool WorkerThread::isCurrentThread() const | 
| return m_thread && m_thread->isCurrentThread(); | 
| } | 
| +void WorkerThread::queueUpIdleHandlerNow(long long delayMs) | 
| +{ | 
| + OwnPtr<WorkerThreadTask> idleHandlerTask = WorkerThreadTask::create(*this, | 
| 
jochen (gone - plz use gerrit)
2014/10/14 13:46:03
nit, put on one line
 
Mayur Kankanwadi
2014/11/04 06:36:58
Done.
 | 
| + createSameThreadTask(&WorkerThread::idleHandler, this), true); | 
| + idleHandlerTask.get()->setIsIdleHandlerTask(true); | 
| 
jochen (gone - plz use gerrit)
2014/10/14 13:46:03
should work without get()
 
Mayur Kankanwadi
2014/11/04 06:36:58
Done.
 | 
| + m_thread->postDelayedTask(idleHandlerTask.leakPtr(), delayMs); | 
| + m_IdleHandlerTaskPosted = true; | 
| +} | 
| + | 
| void WorkerThread::idleHandler() | 
| { | 
| ASSERT(m_workerGlobalScope.get()); | 
| int64 delay = kLongIdleHandlerDelayMs; | 
| + // Some tasks may have been started in the mean time, so lets return back | 
| + // and wait for the next idleHandler to be fired. | 
| + if (m_tasksCount) { | 
| + m_IdleHandlerTaskPosted = false; | 
| 
jochen (gone - plz use gerrit)
2014/10/14 13:46:03
nit. move this up outside the if()
 
Mayur Kankanwadi
2014/11/04 06:36:58
Done.
 | 
| + return; | 
| + } | 
| // Do a script engine idle notification if the next event is distant enough. | 
| const double kMinIdleTimespan = 0.3; | 
| + // This is set to true when idleNotification returns false. | 
| + // idleNotification returns false only when more GC is required. It returns | 
| + // true if no more GC is required and that is when callGCAgain will be set to false. | 
| + bool callGCAgain = false; | 
| if (m_sharedTimer->nextFireTime() == 0.0 || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) { | 
| - bool hasMoreWork = !m_workerGlobalScope->idleNotification(); | 
| - if (hasMoreWork) | 
| + callGCAgain = !m_workerGlobalScope->idleNotification(); | 
| + if (callGCAgain) | 
| delay = kShortIdleHandlerDelayMs; | 
| } | 
| + if (callGCAgain) | 
| + queueUpIdleHandlerNow(delay); | 
| 
jochen (gone - plz use gerrit)
2014/10/14 13:46:03
should be 0
 | 
| + else | 
| + m_IdleHandlerTaskPosted = false; | 
| 
jochen (gone - plz use gerrit)
2014/10/14 13:46:03
not needed anymore after the one above is mvoed
 
Mayur Kankanwadi
2014/11/04 06:36:58
Done.
 | 
| +} | 
| - postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), delay); | 
| +int WorkerThread::decrementAndReturnTaskCount() | 
| +{ | 
| + atomicDecrement(&m_tasksCount); | 
| + return m_tasksCount; | 
| } | 
| void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task) | 
| { | 
| + atomicIncrement(&m_tasksCount); | 
| m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr()); | 
| } | 
| void WorkerThread::postDelayedTask(PassOwnPtr<ExecutionContextTask> task, long long delayMs) | 
| { | 
| + atomicIncrement(&m_tasksCount); | 
| m_thread->postDelayedTask(WorkerThreadTask::create(*this, task, true).leakPtr(), delayMs); | 
| } |