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

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

Issue 1111693003: Remove the concept of a cleanup task (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Potential shutdown sequence with some debug logging. Created 5 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | Source/modules/webdatabase/DatabaseTracker.cpp » ('j') | 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 28 matching lines...) Expand all
39 #include "core/workers/WorkerReportingProxy.h" 39 #include "core/workers/WorkerReportingProxy.h"
40 #include "core/workers/WorkerThreadStartupData.h" 40 #include "core/workers/WorkerThreadStartupData.h"
41 #include "platform/PlatformThreadData.h" 41 #include "platform/PlatformThreadData.h"
42 #include "platform/Task.h" 42 #include "platform/Task.h"
43 #include "platform/ThreadSafeFunctional.h" 43 #include "platform/ThreadSafeFunctional.h"
44 #include "platform/ThreadTimers.h" 44 #include "platform/ThreadTimers.h"
45 #include "platform/heap/SafePoint.h" 45 #include "platform/heap/SafePoint.h"
46 #include "platform/heap/ThreadState.h" 46 #include "platform/heap/ThreadState.h"
47 #include "platform/weborigin/KURL.h" 47 #include "platform/weborigin/KURL.h"
48 #include "public/platform/Platform.h" 48 #include "public/platform/Platform.h"
49 #include "public/platform/WebScheduler.h"
49 #include "public/platform/WebThread.h" 50 #include "public/platform/WebThread.h"
50 #include "public/platform/WebWaitableEvent.h" 51 #include "public/platform/WebWaitableEvent.h"
51 #include "wtf/Noncopyable.h" 52 #include "wtf/Noncopyable.h"
52 #include "wtf/WeakPtr.h" 53 #include "wtf/WeakPtr.h"
53 #include "wtf/text/WTFString.h" 54 #include "wtf/text/WTFString.h"
54 55
55 namespace blink { 56 namespace blink {
56 57
57 namespace { 58 namespace {
58 const int64_t kShortIdleHandlerDelayMs = 1000; 59 const int64_t kShortIdleHandlerDelayMs = 1000;
59 const int64_t kLongIdleHandlerDelayMs = 10*1000; 60 const int64_t kLongIdleHandlerDelayMs = 10*1000;
60 61
61 class MicrotaskRunner : public WebThread::TaskObserver { 62 } // namespace
63
64 class WorkerMicrotaskRunner : public WebThread::TaskObserver {
62 public: 65 public:
63 explicit MicrotaskRunner(WorkerThread* workerThread) 66 explicit WorkerMicrotaskRunner(WorkerThread* workerThread)
64 : m_workerThread(workerThread) 67 : m_workerThread(workerThread)
68 , m_wasClosed(false)
65 { 69 {
66 } 70 }
67 71
68 virtual void willProcessTask() override { } 72 virtual void willProcessTask() override
73 {
74 // No tasks should get executed after we have closed.
75 ASSERT(!m_wasClosed);
76 fprintf(stderr, "%ld: WorkerThread: will process task\n", Platform::curr ent()->currentThread()->threadId());
77 }
78
69 virtual void didProcessTask() override 79 virtual void didProcessTask() override
70 { 80 {
71 Microtask::performCheckpoint(); 81 Microtask::performCheckpoint();
72 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope() ) { 82 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope() ) {
73 if (WorkerScriptController* scriptController = globalScope->script() ) 83 if (WorkerScriptController* scriptController = globalScope->script() )
74 scriptController->rejectedPromises()->processQueue(); 84 scriptController->rejectedPromises()->processQueue();
85 if (globalScope->isClosing()) {
86 m_wasClosed = true;
87 fprintf(stderr, "GLOBAL SCOPE CLOSING\n");
88 m_workerThread->workerReportingProxy().workerGlobalScopeClosed() ;
89 m_workerThread->cleanup();
90 fprintf(stderr, "SCOPE CLOSED\n");
91 }
75 } 92 }
76 } 93 }
77 94
78 private: 95 private:
79 // Thread owns the microtask runner; reference remains 96 // Thread owns the microtask runner; reference remains
80 // valid for the lifetime of this object. 97 // valid for the lifetime of this object.
81 WorkerThread* m_workerThread; 98 WorkerThread* m_workerThread;
99
100 bool m_wasClosed;
82 }; 101 };
83 102
84 } // namespace
85
86 static Mutex& threadSetMutex() 103 static Mutex& threadSetMutex()
87 { 104 {
88 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); 105 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex);
89 return mutex; 106 return mutex;
90 } 107 }
91 108
92 static HashSet<WorkerThread*>& workerThreads() 109 static HashSet<WorkerThread*>& workerThreads()
93 { 110 {
94 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); 111 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ());
95 return threads; 112 return threads;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO wnPtr<ExecutionContextTask> task, bool isInstrumented) 218 static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO wnPtr<ExecutionContextTask> task, bool isInstrumented)
202 { 219 {
203 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented) ); 220 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented) );
204 } 221 }
205 222
206 virtual ~WorkerThreadTask() { } 223 virtual ~WorkerThreadTask() { }
207 224
208 virtual void run() override 225 virtual void run() override
209 { 226 {
210 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope( ); 227 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope( );
211 // Tasks could be put on the message loop after the cleanup task, 228 ASSERT(workerGlobalScope);
212 // ensure none of those are ran.
213 if (!workerGlobalScope)
214 return;
215 229
216 if (m_isInstrumented) 230 if (m_isInstrumented)
217 InspectorInstrumentation::willPerformExecutionContextTask(workerGlob alScope, m_task.get()); 231 InspectorInstrumentation::willPerformExecutionContextTask(workerGlob alScope, m_task.get());
218 if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask()) 232 m_task->performTask(workerGlobalScope);
219 m_task->performTask(workerGlobalScope);
220 if (m_isInstrumented) 233 if (m_isInstrumented)
221 InspectorInstrumentation::didPerformExecutionContextTask(workerGloba lScope); 234 InspectorInstrumentation::didPerformExecutionContextTask(workerGloba lScope);
222 } 235 }
223 236
224 private: 237 private:
225 WorkerThreadTask(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask > task, bool isInstrumented) 238 WorkerThreadTask(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask > task, bool isInstrumented)
226 : m_workerThread(workerThread) 239 : m_workerThread(workerThread)
227 , m_task(task) 240 , m_task(task)
228 , m_isInstrumented(isInstrumented) 241 , m_isInstrumented(isInstrumented)
229 { 242 {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 MutexLocker lock(m_threadCreationMutex); 325 MutexLocker lock(m_threadCreationMutex);
313 326
314 // The worker was terminated before the thread had a chance to run. 327 // The worker was terminated before the thread had a chance to run.
315 if (m_terminated) { 328 if (m_terminated) {
316 // Notify the proxy that the WorkerGlobalScope has been disposed of. 329 // Notify the proxy that the WorkerGlobalScope has been disposed of.
317 // This can free this thread object, hence it must not be touched af terwards. 330 // This can free this thread object, hence it must not be touched af terwards.
318 m_workerReportingProxy.workerThreadTerminated(); 331 m_workerReportingProxy.workerThreadTerminated();
319 return; 332 return;
320 } 333 }
321 334
322 m_microtaskRunner = adoptPtr(new MicrotaskRunner(this)); 335 m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this));
323 backingThread().addTaskObserver(m_microtaskRunner.get()); 336 backingThread().addTaskObserver(m_microtaskRunner.get());
324 backingThread().attachGC(); 337 backingThread().attachGC();
325 338
326 m_isolate = initializeIsolate(); 339 m_isolate = initializeIsolate();
327 m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release()); 340 m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release());
328 m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.ge t() ? cachedMetaData->size() : 0); 341 m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.ge t() ? cachedMetaData->size() : 0);
329 342
330 PlatformThreadData::current().threadTimers().setSharedTimer(adoptPtr(new WorkerSharedTimer(this))); 343 PlatformThreadData::current().threadTimers().setSharedTimer(adoptPtr(new WorkerSharedTimer(this)));
331 } 344 }
332 345
(...skipping 14 matching lines...) Expand all
347 m_workerGlobalScope->didEvaluateWorkerScript(); 360 m_workerGlobalScope->didEvaluateWorkerScript();
348 m_workerReportingProxy.didEvaluateWorkerScript(success); 361 m_workerReportingProxy.didEvaluateWorkerScript(success);
349 362
350 postInitialize(); 363 postInitialize();
351 364
352 postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, this), kShortIdleHandlerDelayMs); 365 postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, this), kShortIdleHandlerDelayMs);
353 } 366 }
354 367
355 void WorkerThread::cleanup() 368 void WorkerThread::cleanup()
356 { 369 {
370 fprintf(stderr, "%ld: WorkerThread::cleanup\n", Platform::current()->current Thread()->threadId());
371 ASSERT(isCurrentThread());
372 workerGlobalScope()->stopActiveDOMObjects();
373 PlatformThreadData::current().threadTimers().setSharedTimer(nullptr);
374
375 // Event listeners would keep DOMWrapperWorld objects alive for too long. Al so, they have references to JS objects,
376 // which become dangling once Heap is destroyed.
377 workerGlobalScope()->removeAllEventListeners();
378 workerGlobalScope()->dispose();
379
380 willDestroyIsolate();
381
357 // This should be called before we start the shutdown procedure. 382 // This should be called before we start the shutdown procedure.
358 workerReportingProxy().willDestroyWorkerGlobalScope(); 383 workerReportingProxy().willDestroyWorkerGlobalScope();
359 384
360 // The below assignment will destroy the context, which will in turn notify messaging proxy. 385 // The below assignment will destroy the context, which will in turn notify messaging proxy.
361 // We cannot let any objects survive past thread exit, because no other thre ad will run GC or otherwise destroy them. 386 // We cannot let any objects survive past thread exit, because no other thre ad will run GC or otherwise destroy them.
362 // If Oilpan is enabled, we detach of the context/global scope, with the fin al heap cleanup below sweeping it out. 387 // If Oilpan is enabled, we detach of the context/global scope, with the fin al heap cleanup below sweeping it out.
363 #if !ENABLE(OILPAN) 388 #if !ENABLE(OILPAN)
364 ASSERT(m_workerGlobalScope->hasOneRef()); 389 ASSERT(m_workerGlobalScope->hasOneRef());
365 #endif 390 #endif
366 m_workerGlobalScope->notifyContextDestroyed(); 391 m_workerGlobalScope->notifyContextDestroyed();
367 m_workerGlobalScope = nullptr; 392 m_workerGlobalScope = nullptr;
368 393
369 backingThread().detachGC(); 394 backingThread().detachGC();
370 destroyIsolate(); 395 destroyIsolate();
371 396
372 backingThread().removeTaskObserver(m_microtaskRunner.get()); 397 backingThread().removeTaskObserver(m_microtaskRunner.get());
373 m_microtaskRunner = nullptr; 398 m_microtaskRunner = nullptr;
374 399
400 // Ensure no posted tasks will run from this point on.
401 backingThread().platformThread().scheduler()->shutdown();
402
375 // Notify the proxy that the WorkerGlobalScope has been disposed of. 403 // Notify the proxy that the WorkerGlobalScope has been disposed of.
376 // This can free this thread object, hence it must not be touched afterwards . 404 // This can free this thread object, hence it must not be touched afterwards .
377 workerReportingProxy().workerThreadTerminated(); 405 workerReportingProxy().workerThreadTerminated();
378 406
379 m_terminationEvent->signal(); 407 m_terminationEvent->signal();
380 408
381 // Clean up PlatformThreadData before WTF::WTFThreadData goes away! 409 // Clean up PlatformThreadData before WTF::WTFThreadData goes away!
382 PlatformThreadData::current().destroy(); 410 PlatformThreadData::current().destroy();
411 fprintf(stderr, "%ld: WorkerThread::cleanup done\n", Platform::current()->cu rrentThread()->threadId());
383 } 412 }
384 413
385 class WorkerThreadShutdownFinishTask : public ExecutionContextTask {
386 public:
387 static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
388 {
389 return adoptPtr(new WorkerThreadShutdownFinishTask());
390 }
391
392 virtual void performTask(ExecutionContext *context)
393 {
394 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
395 workerGlobalScope->dispose();
396
397 WorkerThread* workerThread = workerGlobalScope->thread();
398 workerThread->willDestroyIsolate();
399 workerThread->backingThread().postTask(FROM_HERE, new Task(WTF::bind(&Wo rkerThread::cleanup, workerThread)));
400 }
401
402 virtual bool isCleanupTask() const { return true; }
403 };
404
405 class WorkerThreadShutdownStartTask : public ExecutionContextTask {
406 public:
407 static PassOwnPtr<WorkerThreadShutdownStartTask> create()
408 {
409 return adoptPtr(new WorkerThreadShutdownStartTask());
410 }
411
412 virtual void performTask(ExecutionContext *context)
413 {
414 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
415 workerGlobalScope->stopActiveDOMObjects();
416 PlatformThreadData::current().threadTimers().setSharedTimer(nullptr);
417
418 // Event listeners would keep DOMWrapperWorld objects alive for too long . Also, they have references to JS objects,
419 // which become dangling once Heap is destroyed.
420 workerGlobalScope->removeAllEventListeners();
421
422 // Stick a shutdown command at the end of the queue, so that we deal
423 // with all the cleanup tasks the databases post first.
424 workerGlobalScope->postTask(FROM_HERE, WorkerThreadShutdownFinishTask::c reate());
425 }
426
427 virtual bool isCleanupTask() const { return true; }
alex clarke (OOO till 29th) 2015/05/05 17:45:05 I wonder if you can now remove this from Execution
Sami 2015/05/06 17:37:32 Did you mean isCleanupTask()? Yes, there's no need
428 };
429 414
430 void WorkerThread::stop() 415 void WorkerThread::stop()
431 { 416 {
417 fprintf(stderr, "%ld: WorkerThread::stop\n", Platform::current()->currentThr ead()->threadId());
432 // Prevent the deadlock between GC and an attempt to stop a thread. 418 // Prevent the deadlock between GC and an attempt to stop a thread.
433 SafePointScope safePointScope(ThreadState::HeapPointersOnStack); 419 SafePointScope safePointScope(ThreadState::HeapPointersOnStack);
434 stopInternal(); 420 stopInternal();
435 } 421 }
436 422
437 void WorkerThread::stopInShutdownSequence() 423 void WorkerThread::stopInShutdownSequence()
438 { 424 {
425 fprintf(stderr, "%ld: WorkerThread::stopInShutdownSequence\n", Platform::cur rent()->currentThread()->threadId());
439 stopInternal(); 426 stopInternal();
440 } 427 }
441 428
442 void WorkerThread::terminateAndWait() 429 void WorkerThread::terminateAndWait()
443 { 430 {
431 fprintf(stderr, "%ld: WorkerThread::terminateAndWait\n", Platform::current() ->currentThread()->threadId());
444 stop(); 432 stop();
445 m_terminationEvent->wait(); 433 m_terminationEvent->wait();
446 } 434 }
447 435
448 bool WorkerThread::terminated() 436 bool WorkerThread::terminated()
449 { 437 {
450 MutexLocker lock(m_threadCreationMutex); 438 MutexLocker lock(m_threadCreationMutex);
451 return m_terminated; 439 return m_terminated;
452 } 440 }
453 441
454 void WorkerThread::stopInternal() 442 void WorkerThread::stopInternal()
455 { 443 {
444 fprintf(stderr, "WorkerThread::stopInternal\n");
445
456 // Protect against this method and initialize() racing each other. 446 // Protect against this method and initialize() racing each other.
457 MutexLocker lock(m_threadCreationMutex); 447 MutexLocker lock(m_threadCreationMutex);
458 448
459 // If stop has already been called, just return. 449 // If stop has already been called, just return.
460 if (m_terminated) 450 if (m_terminated)
461 return; 451 return;
462 m_terminated = true; 452 m_terminated = true;
463 453
464 // Signal the thread to notify that the thread's stopping. 454 // Signal the thread to notify that the thread's stopping.
465 if (m_shutdownEvent) 455 if (m_shutdownEvent)
466 m_shutdownEvent->signal(); 456 m_shutdownEvent->signal();
467 457
468 if (!m_workerGlobalScope) 458 if (!m_workerGlobalScope)
469 return; 459 return;
470 460
471 // Ensure that tasks are being handled by thread event loop. If script execu tion weren't forbidden, a while(1) loop in JS could keep the thread alive foreve r. 461 // Ensure that tasks are being handled by thread event loop. If script execu tion weren't forbidden, a while(1) loop in JS could keep the thread alive foreve r.
472 terminateV8Execution(); 462 terminateV8Execution();
473 463
474 InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScop e.get()); 464 InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScop e.get());
475 m_debuggerMessageQueue.kill(); 465 m_debuggerMessageQueue.kill();
476 postTask(FROM_HERE, WorkerThreadShutdownStartTask::create()); 466 backingThread().postTask(FROM_HERE, new Task(threadSafeBind(&WorkerThread::c leanup, AllowCrossThreadAccess(this))));
477 } 467 }
478 468
479 void WorkerThread::didStartRunLoop() 469 void WorkerThread::didStartRunLoop()
480 { 470 {
481 ASSERT(isCurrentThread()); 471 ASSERT(isCurrentThread());
482 Platform::current()->didStartWorkerRunLoop(); 472 Platform::current()->didStartWorkerRunLoop();
483 } 473 }
484 474
485 void WorkerThread::didStopRunLoop() 475 void WorkerThread::didStopRunLoop()
486 { 476 {
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get()); 596 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get());
607 } 597 }
608 598
609 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke rInspectorController) 599 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke rInspectorController)
610 { 600 {
611 MutexLocker locker(m_workerInspectorControllerMutex); 601 MutexLocker locker(m_workerInspectorControllerMutex);
612 m_workerInspectorController = workerInspectorController; 602 m_workerInspectorController = workerInspectorController;
613 } 603 }
614 604
615 } // namespace blink 605 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | Source/modules/webdatabase/DatabaseTracker.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698