Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

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: Updated logic to cancel events and other nits. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 m_sharedTimerFunction(); 173 m_sharedTimerFunction();
174 } 174 }
175 175
176 WorkerThread* m_workerThread; 176 WorkerThread* m_workerThread;
177 SharedTimerFunction m_sharedTimerFunction; 177 SharedTimerFunction m_sharedTimerFunction;
178 double m_nextFireTime; 178 double m_nextFireTime;
179 bool m_running; 179 bool m_running;
180 WorkerThreadCancelableTask* m_lastQueuedTask; 180 WorkerThreadCancelableTask* m_lastQueuedTask;
181 }; 181 };
182 182
183 class WorkerThreadTask : public blink::WebThread::Task { 183 // WorkerThreadTask made private to WorkerThread
184 WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED; 184 PassOwnPtr<WorkerThread::WorkerThreadTask> WorkerThread::WorkerThreadTask::creat e(WorkerThread& workerThread
185 public: 185 , PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
186 static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO wnPtr<ExecutionContextTask> task, bool isInstrumented) 186 {
187 { 187 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented));
188 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented) ); 188 }
189
190 void WorkerThread::WorkerThreadTask::run()
191 {
192 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope();
193 // Tasks could be put on the message loop after the cleanup task,
194 // ensure none of those are ran.
195 if (!workerGlobalScope || m_isTaskCanceled)
196 return;
197
198 if (m_isInstrumented)
199 InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalSc ope, m_task.get());
200 if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_t ask->isCleanupTask()) {
201 if (!m_isIdleHandlerTask || (m_isIdleHandlerTask && !m_workerThread.task Count()))
202 m_task->performTask(workerGlobalScope);
189 } 203 }
204 if (m_isInstrumented)
205 InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalSco pe);
190 206
191 virtual ~WorkerThreadTask() { } 207 // If no more tasks are queued up after this, then queue up the idleHandler
208 // to trigger GC.
209 if (!m_isIdleHandlerTask && !m_workerThread.decrementAndReturnTaskCount() && !m_workerThread.m_lastQueuedIdleHandlerTask)
210 m_workerThread.queueUpIdleHandlerNow(kLongIdleHandlerDelayMs);
211 }
192 212
193 virtual void run() override 213 WorkerThread::WorkerThreadTask::WorkerThreadTask(WorkerThread& workerThread
194 { 214 , PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
195 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope( ); 215 : m_workerThread(workerThread)
196 // Tasks could be put on the message loop after the cleanup task, 216 , m_task(task)
197 // ensure none of those are ran. 217 , m_isInstrumented(isInstrumented)
198 if (!workerGlobalScope) 218 , m_isIdleHandlerTask(false)
199 return; 219 , m_isTaskCanceled(false)
200 220 , m_timeStamp(currentTime())
201 if (m_isInstrumented) 221 {
202 InspectorInstrumentation::willPerformExecutionContextTask(workerGlob alScope, m_task.get()); 222 if (m_isInstrumented)
203 if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask()) 223 m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty();
204 m_task->performTask(workerGlobalScope); 224 if (m_isInstrumented)
205 if (m_isInstrumented) 225 InspectorInstrumentation::didPostExecutionContextTask(m_workerThread.wor kerGlobalScope(), m_task.get());
206 InspectorInstrumentation::didPerformExecutionContextTask(workerGloba lScope); 226 }
207 }
208
209 private:
210 WorkerThreadTask(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask > task, bool isInstrumented)
211 : m_workerThread(workerThread)
212 , m_task(task)
213 , m_isInstrumented(isInstrumented)
214 {
215 if (m_isInstrumented)
216 m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty();
217 if (m_isInstrumented)
218 InspectorInstrumentation::didPostExecutionContextTask(m_workerThread .workerGlobalScope(), m_task.get());
219 }
220
221 WorkerThread& m_workerThread;
222 OwnPtr<ExecutionContextTask> m_task;
223 bool m_isInstrumented;
224 };
225 227
226 class RunDebuggerQueueTask final : public ExecutionContextTask { 228 class RunDebuggerQueueTask final : public ExecutionContextTask {
227 public: 229 public:
228 static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread) 230 static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread)
229 { 231 {
230 return adoptPtr(new RunDebuggerQueueTask(thread)); 232 return adoptPtr(new RunDebuggerQueueTask(thread));
231 } 233 }
232 virtual void performTask(ExecutionContext* context) override 234 virtual void performTask(ExecutionContext* context) override
233 { 235 {
234 ASSERT(context->isWorkerGlobalScope()); 236 ASSERT(context->isWorkerGlobalScope());
235 m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage); 237 m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage);
236 } 238 }
237 239
238 private: 240 private:
239 explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { } 241 explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { }
240 242
241 WorkerThread* m_thread; 243 WorkerThread* m_thread;
242 }; 244 };
243 245
244 WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReporting Proxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> sta rtupData) 246 WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReporting Proxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> sta rtupData)
245 : m_terminated(false) 247 : m_terminated(false)
246 , m_workerLoaderProxy(workerLoaderProxy) 248 , m_workerLoaderProxy(workerLoaderProxy)
247 , m_workerReportingProxy(workerReportingProxy) 249 , m_workerReportingProxy(workerReportingProxy)
248 , m_startupData(startupData) 250 , m_startupData(startupData)
249 , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent() )) 251 , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent() ))
250 , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEven t())) 252 , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEven t()))
253 , m_lastQueuedIdleHandlerTask(nullptr)
254 , m_tasksCount(0)
251 { 255 {
252 MutexLocker lock(threadSetMutex()); 256 MutexLocker lock(threadSetMutex());
253 workerThreads().add(this); 257 workerThreads().add(this);
254 } 258 }
255 259
256 WorkerThread::~WorkerThread() 260 WorkerThread::~WorkerThread()
257 { 261 {
258 MutexLocker lock(threadSetMutex()); 262 MutexLocker lock(threadSetMutex());
259 ASSERT(workerThreads().contains(this)); 263 ASSERT(workerThreads().contains(this));
260 workerThreads().remove(this); 264 workerThreads().remove(this);
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 script->evaluate(ScriptSourceCode(sourceCode, scriptURL)); 327 script->evaluate(ScriptSourceCode(sourceCode, scriptURL));
324 m_workerGlobalScope->didEvaluateWorkerScript(); 328 m_workerGlobalScope->didEvaluateWorkerScript();
325 329
326 postInitialize(); 330 postInitialize();
327 331
328 postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), kSho rtIdleHandlerDelayMs); 332 postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), kSho rtIdleHandlerDelayMs);
329 } 333 }
330 334
331 void WorkerThread::cleanup() 335 void WorkerThread::cleanup()
332 { 336 {
333
334 // This should be called before we start the shutdown procedure. 337 // This should be called before we start the shutdown procedure.
335 workerReportingProxy().willDestroyWorkerGlobalScope(); 338 workerReportingProxy().willDestroyWorkerGlobalScope();
336 339
337 // The below assignment will destroy the context, which will in turn notify messaging proxy. 340 // The below assignment will destroy the context, which will in turn notify messaging proxy.
338 // We cannot let any objects survive past thread exit, because no other thre ad will run GC or otherwise destroy them. 341 // We cannot let any objects survive past thread exit, because no other thre ad will run GC or otherwise destroy them.
339 // If Oilpan is enabled, we detach of the context/global scope, with the fin al heap cleanup below sweeping it out. 342 // If Oilpan is enabled, we detach of the context/global scope, with the fin al heap cleanup below sweeping it out.
340 #if !ENABLE(OILPAN) 343 #if !ENABLE(OILPAN)
341 ASSERT(m_workerGlobalScope->hasOneRef()); 344 ASSERT(m_workerGlobalScope->hasOneRef());
342 #endif 345 #endif
343 m_workerGlobalScope->dispose(); 346 m_workerGlobalScope->dispose();
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 458
456 for (WorkerThread* thread : threads) 459 for (WorkerThread* thread : threads)
457 thread->terminationEvent()->wait(); 460 thread->terminationEvent()->wait();
458 } 461 }
459 462
460 bool WorkerThread::isCurrentThread() const 463 bool WorkerThread::isCurrentThread() const
461 { 464 {
462 return m_thread && m_thread->isCurrentThread(); 465 return m_thread && m_thread->isCurrentThread();
463 } 466 }
464 467
468 void WorkerThread::queueUpIdleHandlerNow(long long delayMs)
469 {
470 OwnPtr<WorkerThreadTask> idleHandlerTask = WorkerThreadTask::create(*this, c reateSameThreadTask(&WorkerThread::idleHandler, this), true);
471
472 idleHandlerTask->setIsIdleHandlerTask(true);
473
474 if (clearIdleHandlerTaskIfSet()) {
475 WorkerThreadTask* tmp = idleHandlerTask.get();
476 m_thread->postDelayedTask(idleHandlerTask.leakPtr(), delayMs);
477 m_lastQueuedIdleHandlerTask = tmp;
478 }
479 }
480
465 void WorkerThread::idleHandler() 481 void WorkerThread::idleHandler()
466 { 482 {
467 ASSERT(m_workerGlobalScope.get()); 483 ASSERT(m_workerGlobalScope.get());
468 int64_t delay = kLongIdleHandlerDelayMs; 484 int64_t delay = kLongIdleHandlerDelayMs;
485 m_lastQueuedIdleHandlerTask = nullptr;
486
487 // Some tasks may have been started in the mean time, so lets return back
488 // and wait for the next idleHandler to be fired.
489 if (m_tasksCount)
490 return;
469 491
470 // Do a script engine idle notification if the next event is distant enough. 492 // Do a script engine idle notification if the next event is distant enough.
471 const double kMinIdleTimespan = 0.3; 493 const double kMinIdleTimespan = 0.3;
494 // This is set to true when idleNotification returns false.
495 // idleNotification returns false only when more GC is required. It returns
496 // true if no more GC is required and that is when callGCAgain will be set t o false.
497 bool callGCAgain = false;
472 if (m_sharedTimer->nextFireTime() == 0.0 || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) { 498 if (m_sharedTimer->nextFireTime() == 0.0 || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) {
473 bool hasMoreWork = !m_workerGlobalScope->idleNotification(); 499 callGCAgain = !m_workerGlobalScope->idleNotification();
474 if (hasMoreWork) 500 if (callGCAgain)
475 delay = kShortIdleHandlerDelayMs; 501 delay = kShortIdleHandlerDelayMs;
476 } 502 }
477 503
478 postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), dela y); 504 if (callGCAgain)
505 queueUpIdleHandlerNow(delay);
506 }
507
508 int WorkerThread::decrementAndReturnTaskCount()
509 {
510 atomicDecrement(&m_tasksCount);
511 return m_tasksCount;
512 }
513
514 bool WorkerThread::clearIdleHandlerTaskIfSet()
515 {
516 // If the event was created more than 3 seconds ago, so its too close to the task completion
517 // hence cancel it and create a new one.
518 const double kIdleHandlerAgeThreshold = 3.0;
519 if (!m_lastQueuedIdleHandlerTask)
520 return true;
521 double idleTaskHandlerAge = currentTime() - m_lastQueuedIdleHandlerTask->cre ationTimeStamp();
522 if (idleTaskHandlerAge < kIdleHandlerAgeThreshold)
523 return false;
524
525 m_lastQueuedIdleHandlerTask->cancelTask();
526 m_lastQueuedIdleHandlerTask = nullptr;
527
528 return true;
479 } 529 }
480 530
481 void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task) 531 void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task)
482 { 532 {
533 atomicIncrement(&m_tasksCount);
534 clearIdleHandlerTaskIfSet();
483 m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr()); 535 m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr());
484 } 536 }
485 537
486 void WorkerThread::postDelayedTask(PassOwnPtr<ExecutionContextTask> task, long l ong delayMs) 538 void WorkerThread::postDelayedTask(PassOwnPtr<ExecutionContextTask> task, long l ong delayMs)
487 { 539 {
540 atomicIncrement(&m_tasksCount);
541 clearIdleHandlerTaskIfSet();
488 m_thread->postDelayedTask(WorkerThreadTask::create(*this, task, true).leakPt r(), delayMs); 542 m_thread->postDelayedTask(WorkerThreadTask::create(*this, task, true).leakPt r(), delayMs);
489 } 543 }
490 544
491 void WorkerThread::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task) 545 void WorkerThread::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task)
492 { 546 {
493 m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false)); 547 m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false));
494 postTask(RunDebuggerQueueTask::create(this)); 548 postTask(RunDebuggerQueueTask::create(this));
495 } 549 }
496 550
497 MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode) 551 MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode)
(...skipping 28 matching lines...) Expand all
526 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get()); 580 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get());
527 } 581 }
528 582
529 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke rInspectorController) 583 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke rInspectorController)
530 { 584 {
531 MutexLocker locker(m_workerInspectorControllerMutex); 585 MutexLocker locker(m_workerInspectorControllerMutex);
532 m_workerInspectorController = workerInspectorController; 586 m_workerInspectorController = workerInspectorController;
533 } 587 }
534 588
535 } // namespace blink 589 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698