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

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

Issue 1978163002: Worker: Initiate worker thread shutdown always on the main thread (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address review comments Created 4 years, 7 months 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 | « third_party/WebKit/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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 DCHECK(!m_workerThread->workerGlobalScope() || !m_workerThread->workerGl obalScope()->isClosing()); 65 DCHECK(!m_workerThread->workerGlobalScope() || !m_workerThread->workerGl obalScope()->isClosing());
66 } 66 }
67 67
68 void didProcessTask() override 68 void didProcessTask() override
69 { 69 {
70 Microtask::performCheckpoint(m_workerThread->isolate()); 70 Microtask::performCheckpoint(m_workerThread->isolate());
71 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope() ) { 71 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope() ) {
72 if (WorkerOrWorkletScriptController* scriptController = globalScope- >scriptController()) 72 if (WorkerOrWorkletScriptController* scriptController = globalScope- >scriptController())
73 scriptController->getRejectedPromises()->processQueue(); 73 scriptController->getRejectedPromises()->processQueue();
74 if (globalScope->isClosing()) { 74 if (globalScope->isClosing()) {
75 // |m_workerThread| will eventually be requested to terminate.
75 m_workerThread->workerReportingProxy().workerGlobalScopeClosed() ; 76 m_workerThread->workerReportingProxy().workerGlobalScopeClosed() ;
76 m_workerThread->terminateFromWorkerThread(); 77
78 // Dispose WorkerGlobalScope to avoid processing the next task.
79 m_workerThread->prepareForShutdown();
77 } 80 }
78 } 81 }
79 } 82 }
80 83
81 private: 84 private:
82 // Thread owns the microtask runner; reference remains 85 // Thread owns the microtask runner; reference remains
83 // valid for the lifetime of this object. 86 // valid for the lifetime of this object.
84 WorkerThread* m_workerThread; 87 WorkerThread* m_workerThread;
85 }; 88 };
86 89
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 if (isInstrumented) 125 if (isInstrumented)
123 isInstrumented = !task->taskNameForInstrumentation().isEmpty(); 126 isInstrumented = !task->taskNameForInstrumentation().isEmpty();
124 if (isInstrumented) { 127 if (isInstrumented) {
125 DCHECK(isCurrentThread()); 128 DCHECK(isCurrentThread());
126 InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worke r task", task.get()); 129 InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worke r task", task.get());
127 } 130 }
128 return threadSafeBind(&WorkerThread::performTask, AllowCrossThreadAccess(thi s), passed(std::move(task)), isInstrumented); 131 return threadSafeBind(&WorkerThread::performTask, AllowCrossThreadAccess(thi s), passed(std::move(task)), isInstrumented);
129 } 132 }
130 133
131 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work erReportingProxy& workerReportingProxy) 134 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work erReportingProxy& workerReportingProxy)
132 : m_started(false) 135 : m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner()))
133 , m_terminated(false)
134 , m_shutdown(false)
135 , m_pausedInDebugger(false)
136 , m_runningDebuggerTask(false)
137 , m_shouldTerminateV8Execution(false)
138 , m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner()))
139 , m_workerLoaderProxy(workerLoaderProxy) 136 , m_workerLoaderProxy(workerLoaderProxy)
140 , m_workerReportingProxy(workerReportingProxy) 137 , m_workerReportingProxy(workerReportingProxy)
141 , m_webScheduler(nullptr)
142 , m_terminationEvent(adoptPtr(new WaitableEvent( 138 , m_terminationEvent(adoptPtr(new WaitableEvent(
143 WaitableEvent::ResetPolicy::Manual, 139 WaitableEvent::ResetPolicy::Manual,
144 WaitableEvent::InitialState::NonSignaled))) 140 WaitableEvent::InitialState::NonSignaled)))
145 , m_shutdownEvent(adoptPtr(new WaitableEvent( 141 , m_shutdownEvent(adoptPtr(new WaitableEvent(
146 WaitableEvent::ResetPolicy::Manual, 142 WaitableEvent::ResetPolicy::Manual,
147 WaitableEvent::InitialState::NonSignaled))) 143 WaitableEvent::InitialState::NonSignaled)))
148 { 144 {
149 MutexLocker lock(threadSetMutex()); 145 MutexLocker lock(threadSetMutex());
150 workerThreads().add(this); 146 workerThreads().add(this);
151 } 147 }
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourc eCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions); 229 bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourc eCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions);
234 m_workerGlobalScope->didEvaluateWorkerScript(); 230 m_workerGlobalScope->didEvaluateWorkerScript();
235 m_workerReportingProxy.didEvaluateWorkerScript(success); 231 m_workerReportingProxy.didEvaluateWorkerScript(success);
236 232
237 postInitialize(); 233 postInitialize();
238 } 234 }
239 235
240 void WorkerThread::shutdown() 236 void WorkerThread::shutdown()
241 { 237 {
242 DCHECK(isCurrentThread()); 238 DCHECK(isCurrentThread());
243 { 239 prepareForShutdown();
244 MutexLocker lock(m_threadStateMutex);
245 if (m_shutdown)
246 return;
247 m_shutdown = true;
248 }
249
250 // This should be called before we start the shutdown procedure.
251 workerReportingProxy().willDestroyWorkerGlobalScope();
252
253 workerGlobalScope()->dispose();
254
255 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g et());
256 postTask(BLINK_FROM_HERE, createSameThreadTask(&WorkerThread::performShutdow nTask, this)); 240 postTask(BLINK_FROM_HERE, createSameThreadTask(&WorkerThread::performShutdow nTask, this));
257 } 241 }
258 242
259 void WorkerThread::performShutdownTask() 243 void WorkerThread::performShutdownTask()
260 { 244 {
261 DCHECK(isCurrentThread()); 245 DCHECK(isCurrentThread());
yhirano 2016/05/23 10:05:19 It might be good to assert m_terminated && m_ready
nhiroki 2016/05/24 06:50:43 Done.
262 246
263 // The below assignment will destroy the context, which will in turn notify 247 // The below assignment will destroy the context, which will in turn notify
264 // messaging proxy. We cannot let any objects survive past thread exit, 248 // messaging proxy. We cannot let any objects survive past thread exit,
265 // because no other thread will run GC or otherwise destroy them. If Oilpan 249 // because no other thread will run GC or otherwise destroy them. If Oilpan
266 // is enabled, we detach of the context/global scope, with the final heap 250 // is enabled, we detach of the context/global scope, with the final heap
267 // cleanup below sweeping it out. 251 // cleanup below sweeping it out.
268 m_workerGlobalScope->notifyContextDestroyed(); 252 m_workerGlobalScope->notifyContextDestroyed();
269 m_workerGlobalScope = nullptr; 253 m_workerGlobalScope = nullptr;
270 254
271 workerBackingThread().detach(); 255 workerBackingThread().detach();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 // Keep this lock to prevent WorkerThread instances from being destroyed. 287 // Keep this lock to prevent WorkerThread instances from being destroyed.
304 MutexLocker lock(threadSetMutex()); 288 MutexLocker lock(threadSetMutex());
305 HashSet<WorkerThread*> threads = workerThreads(); 289 HashSet<WorkerThread*> threads = workerThreads();
306 for (WorkerThread* thread : threads) 290 for (WorkerThread* thread : threads)
307 thread->terminateInternal(); 291 thread->terminateInternal();
308 292
309 for (WorkerThread* thread : threads) 293 for (WorkerThread* thread : threads)
310 thread->m_shutdownEvent->wait(); 294 thread->m_shutdownEvent->wait();
311 } 295 }
312 296
313 void WorkerThread::terminateFromWorkerThread() 297 void WorkerThread::prepareForShutdown()
314 { 298 {
315 DCHECK(isCurrentThread()); 299 DCHECK(isCurrentThread());
316 shutdown(); 300 {
301 MutexLocker lock(m_threadStateMutex);
302 if (m_readyToShutdown)
303 return;
304 m_readyToShutdown = true;
305 }
306
307 workerReportingProxy().willDestroyWorkerGlobalScope();
308 workerGlobalScope()->dispose();
309 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g et());
317 } 310 }
318 311
319 WorkerGlobalScope* WorkerThread::workerGlobalScope() 312 WorkerGlobalScope* WorkerThread::workerGlobalScope()
320 { 313 {
321 DCHECK(isCurrentThread()); 314 DCHECK(isCurrentThread());
322 return m_workerGlobalScope.get(); 315 return m_workerGlobalScope.get();
323 } 316 }
324 317
325 bool WorkerThread::terminated() 318 bool WorkerThread::terminated()
326 { 319 {
(...skipping 11 matching lines...) Expand all
338 331
339 // If terminateInternal has already been called, just return. 332 // If terminateInternal has already been called, just return.
340 if (m_terminated) 333 if (m_terminated)
341 return; 334 return;
342 m_terminated = true; 335 m_terminated = true;
343 336
344 // Signal the thread to notify that the thread's stopping. 337 // Signal the thread to notify that the thread's stopping.
345 if (m_terminationEvent) 338 if (m_terminationEvent)
346 m_terminationEvent->signal(); 339 m_terminationEvent->signal();
347 340
348 // If the thread has already initiated shutdown, just return.
349 if (m_shutdown)
350 return;
351
352 // If the worker thread was never initialized, don't start another 341 // If the worker thread was never initialized, don't start another
353 // shutdown, but still wait for the thread to signal when shutdown has 342 // shutdown, but still wait for the thread to signal when shutdown has
354 // completed on initialize(). 343 // completed on initialize().
355 if (!m_workerGlobalScope) 344 if (!m_workerGlobalScope)
356 return; 345 return;
357 346
358 // Ensure that tasks are being handled by thread event loop. If script 347 // If |m_readyToShutdown| is set, scriptController() is already disposed.
359 // execution weren't forbidden, a while(1) loop in JS could keep the thread 348 if (!m_readyToShutdown) {
360 // alive forever. 349 DCHECK(m_workerGlobalScope->scriptController());
361 m_workerGlobalScope->scriptController()->willScheduleExecutionTermination(); 350
351 // Ensure that tasks are being handled by thread event loop. If script
352 // execution weren't forbidden, a while(1) loop in JS could keep the thr ead
353 // alive forever.
354 m_workerGlobalScope->scriptController()->willScheduleExecutionTerminatio n();
355 }
362 356
363 if (workerBackingThread().workerScriptCount() == 1) { 357 if (workerBackingThread().workerScriptCount() == 1) {
364 // This condition is not entirely correct because other scripts 358 // This condition is not entirely correct because other scripts
365 // can be being initialized or terminated simuletaneously. Though this 359 // can be being initialized or terminated simuletaneously. Though this
366 // function itself is protected by a mutex, it is possible that 360 // function itself is protected by a mutex, it is possible that
367 // |workerScriptCount()| here is not consistent with that in 361 // |workerScriptCount()| here is not consistent with that in
368 // |initialize| and |shutdown|. 362 // |initialize| and |shutdown|.
369 // TODO(yhirano): TerminateExecution should be called more carefully. 363 // TODO(yhirano): TerminateExecution should be called more carefully.
370 // https://crbug.com/413518 364 // https://crbug.com/413518
371 if (m_runningDebuggerTask) { 365 if (m_runningDebuggerTask) {
372 // Terminating during debugger task may lead to crash due to heavy 366 // Terminating during debugger task may lead to crash due to heavy
373 // use of v8 api in debugger. Any debugger task is guaranteed to 367 // use of v8 api in debugger. Any debugger task is guaranteed to
374 // finish, so we can postpone termination after task has finished. 368 // finish, so we can postpone termination after task has finished.
375 // Note: m_runningDebuggerTask and m_shouldTerminateV8Execution 369 // Note: m_runningDebuggerTask and m_shouldTerminateV8Execution
376 // access must be guarded by the lock. 370 // access must be guarded by the lock.
377 m_shouldTerminateV8Execution = true; 371 m_shouldTerminateV8Execution = true;
378 } else { 372 } else {
379 isolate()->TerminateExecution(); 373 isolate()->TerminateExecution();
380 } 374 }
381 } 375 }
382 376
383 InspectorInstrumentation::allAsyncTasksCanceled(m_workerGlobalScope.get()); 377 InspectorInstrumentation::allAsyncTasksCanceled(m_workerGlobalScope.get());
384 m_inspectorTaskRunner->kill(); 378 m_inspectorTaskRunner->kill();
385 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::shutdown, AllowCrossThreadAccess(this))); 379 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::shutdown, AllowCrossThreadAccess(this)));
yhirano 2016/05/23 10:05:19 Can you post two tasks (prepareForShutdown and per
nhiroki 2016/05/24 06:50:43 Done.
386 } 380 }
387 381
388 v8::Isolate* WorkerThread::isolate() 382 v8::Isolate* WorkerThread::isolate()
389 { 383 {
390 return workerBackingThread().isolate(); 384 return workerBackingThread().isolate();
391 } 385 }
392 386
393 bool WorkerThread::isCurrentThread() 387 bool WorkerThread::isCurrentThread()
394 { 388 {
395 return m_started && workerBackingThread().backingThread().isCurrentThread(); 389 return m_started && workerBackingThread().backingThread().isCurrentThread();
396 } 390 }
397 391
398 void WorkerThread::postTask(const WebTraceLocation& location, std::unique_ptr<Ex ecutionContextTask> task) 392 void WorkerThread::postTask(const WebTraceLocation& location, std::unique_ptr<Ex ecutionContextTask> task)
399 { 393 {
400 workerBackingThread().backingThread().postTask(location, createWorkerThreadT ask(std::move(task), true)); 394 workerBackingThread().backingThread().postTask(location, createWorkerThreadT ask(std::move(task), true));
401 } 395 }
402 396
403 void WorkerThread::runDebuggerTaskDontWait() 397 void WorkerThread::runDebuggerTaskDontWait()
404 { 398 {
405 DCHECK(isCurrentThread()); 399 DCHECK(isCurrentThread());
406 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa sk(InspectorTaskRunner::DontWaitForTask); 400 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa sk(InspectorTaskRunner::DontWaitForTask);
407 if (task) 401 if (task)
408 (*task)(); 402 (*task)();
409 } 403 }
410 404
411 void WorkerThread::appendDebuggerTask(std::unique_ptr<CrossThreadClosure> task) 405 void WorkerThread::appendDebuggerTask(std::unique_ptr<CrossThreadClosure> task)
412 { 406 {
413 { 407 {
414 MutexLocker lock(m_threadStateMutex); 408 MutexLocker lock(m_threadStateMutex);
415 if (m_shutdown) 409 if (m_readyToShutdown)
416 return; 410 return;
417 } 411 }
418 m_inspectorTaskRunner->appendTask(threadSafeBind(&WorkerThread::runDebuggerT ask, AllowCrossThreadAccess(this), passed(std::move(task)))); 412 m_inspectorTaskRunner->appendTask(threadSafeBind(&WorkerThread::runDebuggerT ask, AllowCrossThreadAccess(this), passed(std::move(task))));
419 { 413 {
420 MutexLocker lock(m_threadStateMutex); 414 MutexLocker lock(m_threadStateMutex);
421 if (isolate()) 415 if (isolate())
422 m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate()); 416 m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate());
423 } 417 }
424 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::runDebuggerTaskDontWait, AllowCrossThreadAccess(this))); 418 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::runDebuggerTaskDontWait, AllowCrossThreadAccess(this)));
425 } 419 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 } while (task && m_pausedInDebugger); 455 } while (task && m_pausedInDebugger);
462 ThreadDebugger::idleFinished(isolate()); 456 ThreadDebugger::idleFinished(isolate());
463 } 457 }
464 458
465 void WorkerThread::stopRunningDebuggerTasksOnPause() 459 void WorkerThread::stopRunningDebuggerTasksOnPause()
466 { 460 {
467 m_pausedInDebugger = false; 461 m_pausedInDebugger = false;
468 } 462 }
469 463
470 } // namespace blink 464 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/workers/WorkerThread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698