Chromium Code Reviews

Side by Side Diff: Source/core/workers/WorkerThread.cpp

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
Patch Set: Implemented new idleHandler firing logic. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 27 matching lines...)
38 #include "core/workers/WorkerThreadStartupData.h" 38 #include "core/workers/WorkerThreadStartupData.h"
39 #include "platform/PlatformThreadData.h" 39 #include "platform/PlatformThreadData.h"
40 #include "platform/Task.h" 40 #include "platform/Task.h"
41 #include "platform/ThreadTimers.h" 41 #include "platform/ThreadTimers.h"
42 #include "platform/heap/ThreadState.h" 42 #include "platform/heap/ThreadState.h"
43 #include "platform/weborigin/KURL.h" 43 #include "platform/weborigin/KURL.h"
44 #include "public/platform/Platform.h" 44 #include "public/platform/Platform.h"
45 #include "public/platform/WebThread.h" 45 #include "public/platform/WebThread.h"
46 #include "public/platform/WebWaitableEvent.h" 46 #include "public/platform/WebWaitableEvent.h"
47 #include "public/platform/WebWorkerRunLoop.h" 47 #include "public/platform/WebWorkerRunLoop.h"
48 #include "wtf/Noncopyable.h" 48 #include "wtf/Atomics.h"
49 #include "wtf/text/WTFString.h" 49 #include "wtf/text/WTFString.h"
50 50
51 #include <utility> 51 #include <utility>
52 52
53 namespace blink { 53 namespace blink {
54 54
55 namespace { 55 namespace {
56 const int64 kShortIdleHandlerDelayMs = 1000; 56 const int64 kShortIdleHandlerDelayMs = 1000;
57 const int64 kLongIdleHandlerDelayMs = 10*1000; 57 const int64 kLongIdleHandlerDelayMs = 10*1000;
58 58
(...skipping 112 matching lines...)
171 m_sharedTimerFunction(); 171 m_sharedTimerFunction();
172 } 172 }
173 173
174 WorkerThread* m_workerThread; 174 WorkerThread* m_workerThread;
175 SharedTimerFunction m_sharedTimerFunction; 175 SharedTimerFunction m_sharedTimerFunction;
176 double m_nextFireTime; 176 double m_nextFireTime;
177 bool m_running; 177 bool m_running;
178 WorkerThreadCancelableTask* m_lastQueuedTask; 178 WorkerThreadCancelableTask* m_lastQueuedTask;
179 }; 179 };
180 180
181 class WorkerThreadTask : public blink::WebThread::Task { 181 // WorkerThreadTask made private to WorkerThread
182 WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED;
183 public:
184 static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO wnPtr<ExecutionContextTask> task, bool isInstrumented)
185 {
186 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented) );
187 }
188 182
189 virtual ~WorkerThreadTask() { } 183 PassOwnPtr<WorkerThread::WorkerThreadTask> WorkerThread::WorkerThreadTask::creat e(WorkerThread& workerThread
184 , PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
185 {
186 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented));
187 }
190 188
191 virtual void run() OVERRIDE 189 void WorkerThread::WorkerThreadTask::run()
192 { 190 {
193 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope( ); 191 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope();
194 // Tasks could be put on the message loop after the cleanup task, 192 // Tasks could be put on the message loop after the cleanup task,
195 // ensure none of those are ran. 193 // ensure none of those are ran.
196 if (!workerGlobalScope) 194 if (!workerGlobalScope)
197 return; 195 return;
198 196
199 if (m_isInstrumented) 197 if (m_isInstrumented)
200 InspectorInstrumentation::willPerformExecutionContextTask(workerGlob alScope, m_task.get()); 198 InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalSc ope, m_task.get());
201 if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask()) 199 if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_t ask->isCleanupTask())
200 if (!m_isIdleHandlerTask || (m_isIdleHandlerTask && !m_workerThread.task Count())) {
202 m_task->performTask(workerGlobalScope); 201 m_task->performTask(workerGlobalScope);
203 if (m_isInstrumented) 202 }
204 InspectorInstrumentation::didPerformExecutionContextTask(workerGloba lScope); 203 if (m_isInstrumented)
205 } 204 InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalSco pe);
206 205
207 private: 206 // If no more tasks are queued up after this, then queue up the idleHandler
208 WorkerThreadTask(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask > task, bool isInstrumented) 207 // to trigger GC.
209 : m_workerThread(workerThread) 208 if (!m_isIdleHandlerTask && !m_workerThread.decrementAndReturnTaskCount()
210 , m_task(task) 209 && !m_workerThread.m_IdleHandlerTaskPosted)
jochen (gone - plz use gerrit) 2014/10/14 13:46:03 nit. put on previous line
211 , m_isInstrumented(isInstrumented) 210 m_workerThread.queueUpIdleHandlerNow(kLongIdleHandlerDelayMs);
212 { 211 }
213 if (m_isInstrumented)
214 m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty();
215 if (m_isInstrumented)
216 InspectorInstrumentation::didPostExecutionContextTask(m_workerThread .workerGlobalScope(), m_task.get());
217 }
218 212
219 WorkerThread& m_workerThread; 213 WorkerThread::WorkerThreadTask::WorkerThreadTask(WorkerThread& workerThread
220 OwnPtr<ExecutionContextTask> m_task; 214 , PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
221 bool m_isInstrumented; 215 : m_workerThread(workerThread)
222 }; 216 , m_task(task)
217 , m_isInstrumented(isInstrumented)
218 , m_isIdleHandlerTask(false)
219 {
220 if (m_isInstrumented)
221 m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty();
222 if (m_isInstrumented)
223 InspectorInstrumentation::didPostExecutionContextTask(m_workerThread.wor kerGlobalScope(), m_task.get());
224 }
223 225
224 class RunDebuggerQueueTask FINAL : public ExecutionContextTask { 226 class RunDebuggerQueueTask FINAL : public ExecutionContextTask {
225 public: 227 public:
226 static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread) 228 static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread)
227 { 229 {
228 return adoptPtr(new RunDebuggerQueueTask(thread)); 230 return adoptPtr(new RunDebuggerQueueTask(thread));
229 } 231 }
230 virtual void performTask(ExecutionContext* context) OVERRIDE 232 virtual void performTask(ExecutionContext* context) OVERRIDE
231 { 233 {
232 ASSERT(context->isWorkerGlobalScope()); 234 ASSERT(context->isWorkerGlobalScope());
233 m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage); 235 m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage);
234 } 236 }
235 237
236 private: 238 private:
237 explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { } 239 explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { }
238 240
239 WorkerThread* m_thread; 241 WorkerThread* m_thread;
240 }; 242 };
241 243
242 WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReporting Proxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> sta rtupData) 244 WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReporting Proxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> sta rtupData)
243 : m_terminated(false) 245 : m_terminated(false)
244 , m_workerLoaderProxy(workerLoaderProxy) 246 , m_workerLoaderProxy(workerLoaderProxy)
245 , m_workerReportingProxy(workerReportingProxy) 247 , m_workerReportingProxy(workerReportingProxy)
246 , m_startupData(startupData) 248 , m_startupData(startupData)
247 , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent() )) 249 , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent() ))
248 , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEven t())) 250 , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEven t()))
251 , m_IdleHandlerTaskPosted(false)
252 , m_tasksCount(0)
249 { 253 {
250 MutexLocker lock(threadSetMutex()); 254 MutexLocker lock(threadSetMutex());
251 workerThreads().add(this); 255 workerThreads().add(this);
252 } 256 }
253 257
254 WorkerThread::~WorkerThread() 258 WorkerThread::~WorkerThread()
255 { 259 {
256 MutexLocker lock(threadSetMutex()); 260 MutexLocker lock(threadSetMutex());
257 ASSERT(workerThreads().contains(this)); 261 ASSERT(workerThreads().contains(this));
258 workerThreads().remove(this); 262 workerThreads().remove(this);
(...skipping 55 matching lines...)
314 // Notify proxy that a new WorkerGlobalScope has been created and started. 318 // Notify proxy that a new WorkerGlobalScope has been created and started.
315 m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get()); 319 m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
316 320
317 WorkerScriptController* script = m_workerGlobalScope->script(); 321 WorkerScriptController* script = m_workerGlobalScope->script();
318 if (!script->isExecutionForbidden()) 322 if (!script->isExecutionForbidden())
319 script->initializeContextIfNeeded(); 323 script->initializeContextIfNeeded();
320 InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), star tMode); 324 InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), star tMode);
321 script->evaluate(ScriptSourceCode(sourceCode, scriptURL)); 325 script->evaluate(ScriptSourceCode(sourceCode, scriptURL));
322 326
323 postInitialize(); 327 postInitialize();
324
325 postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), kSho rtIdleHandlerDelayMs);
326 } 328 }
327 329
328 void WorkerThread::cleanup() 330 void WorkerThread::cleanup()
329 { 331 {
330 332
331 // This should be called before we start the shutdown procedure. 333 // This should be called before we start the shutdown procedure.
332 workerReportingProxy().willDestroyWorkerGlobalScope(); 334 workerReportingProxy().willDestroyWorkerGlobalScope();
333 335
334 // The below assignment will destroy the context, which will in turn notify messaging proxy. 336 // The below assignment will destroy the context, which will in turn notify messaging proxy.
335 // We cannot let any objects survive past thread exit, because no other thre ad will run GC or otherwise destroy them. 337 // We cannot let any objects survive past thread exit, because no other thre ad will run GC or otherwise destroy them.
(...skipping 116 matching lines...)
452 454
453 for (HashSet<WorkerThread*>::iterator itr = threads.begin(); itr != threads. end(); ++itr) 455 for (HashSet<WorkerThread*>::iterator itr = threads.begin(); itr != threads. end(); ++itr)
454 (*itr)->terminationEvent()->wait(); 456 (*itr)->terminationEvent()->wait();
455 } 457 }
456 458
457 bool WorkerThread::isCurrentThread() const 459 bool WorkerThread::isCurrentThread() const
458 { 460 {
459 return m_thread && m_thread->isCurrentThread(); 461 return m_thread && m_thread->isCurrentThread();
460 } 462 }
461 463
464 void WorkerThread::queueUpIdleHandlerNow(long long delayMs)
465 {
466 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.
467 createSameThreadTask(&WorkerThread::idleHandler, this), true);
468 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.
469 m_thread->postDelayedTask(idleHandlerTask.leakPtr(), delayMs);
470 m_IdleHandlerTaskPosted = true;
471 }
472
462 void WorkerThread::idleHandler() 473 void WorkerThread::idleHandler()
463 { 474 {
464 ASSERT(m_workerGlobalScope.get()); 475 ASSERT(m_workerGlobalScope.get());
465 int64 delay = kLongIdleHandlerDelayMs; 476 int64 delay = kLongIdleHandlerDelayMs;
466 477
478 // Some tasks may have been started in the mean time, so lets return back
479 // and wait for the next idleHandler to be fired.
480 if (m_tasksCount) {
481 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.
482 return;
483 }
467 // Do a script engine idle notification if the next event is distant enough. 484 // Do a script engine idle notification if the next event is distant enough.
468 const double kMinIdleTimespan = 0.3; 485 const double kMinIdleTimespan = 0.3;
486 // This is set to true when idleNotification returns false.
487 // idleNotification returns false only when more GC is required. It returns
488 // true if no more GC is required and that is when callGCAgain will be set t o false.
489 bool callGCAgain = false;
469 if (m_sharedTimer->nextFireTime() == 0.0 || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) { 490 if (m_sharedTimer->nextFireTime() == 0.0 || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) {
470 bool hasMoreWork = !m_workerGlobalScope->idleNotification(); 491 callGCAgain = !m_workerGlobalScope->idleNotification();
471 if (hasMoreWork) 492 if (callGCAgain)
472 delay = kShortIdleHandlerDelayMs; 493 delay = kShortIdleHandlerDelayMs;
473 } 494 }
495 if (callGCAgain)
496 queueUpIdleHandlerNow(delay);
jochen (gone - plz use gerrit) 2014/10/14 13:46:03 should be 0
497 else
498 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.
499 }
474 500
475 postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), dela y); 501 int WorkerThread::decrementAndReturnTaskCount()
502 {
503 atomicDecrement(&m_tasksCount);
504 return m_tasksCount;
476 } 505 }
477 506
478 void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task) 507 void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task)
479 { 508 {
509 atomicIncrement(&m_tasksCount);
480 m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr()); 510 m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr());
481 } 511 }
482 512
483 void WorkerThread::postDelayedTask(PassOwnPtr<ExecutionContextTask> task, long l ong delayMs) 513 void WorkerThread::postDelayedTask(PassOwnPtr<ExecutionContextTask> task, long l ong delayMs)
484 { 514 {
515 atomicIncrement(&m_tasksCount);
485 m_thread->postDelayedTask(WorkerThreadTask::create(*this, task, true).leakPt r(), delayMs); 516 m_thread->postDelayedTask(WorkerThreadTask::create(*this, task, true).leakPt r(), delayMs);
486 } 517 }
487 518
488 void WorkerThread::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task) 519 void WorkerThread::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task)
489 { 520 {
490 m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false)); 521 m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false));
491 postTask(RunDebuggerQueueTask::create(this)); 522 postTask(RunDebuggerQueueTask::create(this));
492 } 523 }
493 524
494 MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode) 525 MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode)
(...skipping 28 matching lines...)
523 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get()); 554 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get());
524 } 555 }
525 556
526 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke rInspectorController) 557 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke rInspectorController)
527 { 558 {
528 MutexLocker locker(m_workerInspectorControllerMutex); 559 MutexLocker locker(m_workerInspectorControllerMutex);
529 m_workerInspectorController = workerInspectorController; 560 m_workerInspectorController = workerInspectorController;
530 } 561 }
531 562
532 } // namespace blink 563 } // namespace blink
OLDNEW
« Source/core/workers/WorkerThread.h ('K') | « Source/core/workers/WorkerThread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine