Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 24 matching lines...) Expand all Loading... | |
| 35 #include "core/inspector/WorkerThreadDebugger.h" | 35 #include "core/inspector/WorkerThreadDebugger.h" |
| 36 #include "core/workers/WorkerBackingThread.h" | 36 #include "core/workers/WorkerBackingThread.h" |
| 37 #include "core/workers/WorkerClients.h" | 37 #include "core/workers/WorkerClients.h" |
| 38 #include "core/workers/WorkerReportingProxy.h" | 38 #include "core/workers/WorkerReportingProxy.h" |
| 39 #include "core/workers/WorkerThreadStartupData.h" | 39 #include "core/workers/WorkerThreadStartupData.h" |
| 40 #include "platform/ThreadSafeFunctional.h" | 40 #include "platform/ThreadSafeFunctional.h" |
| 41 #include "platform/WaitableEvent.h" | 41 #include "platform/WaitableEvent.h" |
| 42 #include "platform/WebThreadSupportingGC.h" | 42 #include "platform/WebThreadSupportingGC.h" |
| 43 #include "platform/heap/SafePoint.h" | 43 #include "platform/heap/SafePoint.h" |
| 44 #include "platform/heap/ThreadState.h" | 44 #include "platform/heap/ThreadState.h" |
| 45 #include "platform/scheduler/CancellableTaskFactory.h" | |
| 45 #include "platform/weborigin/KURL.h" | 46 #include "platform/weborigin/KURL.h" |
| 46 #include "public/platform/WebThread.h" | 47 #include "public/platform/WebThread.h" |
| 47 #include "wtf/Functional.h" | 48 #include "wtf/Functional.h" |
| 48 #include "wtf/Noncopyable.h" | 49 #include "wtf/Noncopyable.h" |
| 49 #include "wtf/text/WTFString.h" | 50 #include "wtf/text/WTFString.h" |
| 50 #include <limits.h> | 51 #include <limits.h> |
| 51 | 52 |
| 52 namespace blink { | 53 namespace blink { |
| 53 | 54 |
| 54 class WorkerThread::WorkerMicrotaskRunner : public WebThread::TaskObserver { | 55 // TODO(nhiroki): Adjust the delay based on UMA. |
| 56 const long long kForceTerminationDelayInMs = 3000; // 3 secs | |
|
kinuko
2016/05/31 10:13:26
nit: we used to have 2 secs timer to forcibly kill
nhiroki
2016/06/01 04:16:36
Done.
| |
| 57 | |
| 58 // ForceTerminationTask is used for posting a delayed task to terminate an | |
| 59 // isolate from the main thread. This task is expected to run when the shutdown | |
| 60 // sequence does not start in a certain time period because of an inifite loop | |
| 61 // in the JS execution context etc. When the shutdown sequence is started before | |
| 62 // this task runs, the task is simply cancelled. | |
| 63 class WorkerThread::ForceTerminationTask final { | |
| 64 public: | |
| 65 static PassOwnPtr<ForceTerminationTask> create(WorkerThread* workerThread) | |
| 66 { | |
| 67 return adoptPtr(new ForceTerminationTask(workerThread)); | |
| 68 } | |
| 69 | |
| 70 void schedule() | |
| 71 { | |
| 72 DCHECK(isMainThread()); | |
| 73 Platform::current()->mainThread()->getWebTaskRunner()->postDelayedTask(B LINK_FROM_HERE, m_cancellableTaskFactory->cancelAndCreate(), m_workerThread->m_f orceTerminationDelayInMs); | |
| 74 } | |
| 75 | |
| 76 private: | |
| 77 explicit ForceTerminationTask(WorkerThread* workerThread) | |
| 78 : m_workerThread(workerThread) | |
| 79 { | |
| 80 DCHECK(isMainThread()); | |
| 81 m_cancellableTaskFactory = CancellableTaskFactory::create(this, &ForceTe rminationTask::run); | |
| 82 } | |
| 83 | |
| 84 void run() | |
| 85 { | |
| 86 DCHECK(isMainThread()); | |
| 87 MutexLocker lock(m_workerThread->m_threadStateMutex); | |
| 88 if (m_workerThread->m_readyToShutdown) { | |
| 89 // Shutdown sequence is now running. Just return. | |
| 90 return; | |
| 91 } | |
| 92 | |
| 93 m_workerThread->forciblyTerminateIsolate(); | |
| 94 DCHECK_EQ(WorkerThread::ExitCode::NotTerminated, m_workerThread->m_exitC ode); | |
| 95 m_workerThread->m_exitCode = WorkerThread::ExitCode::AsyncForciblyTermin ated; | |
| 96 } | |
| 97 | |
| 98 WorkerThread* m_workerThread; | |
| 99 OwnPtr<CancellableTaskFactory> m_cancellableTaskFactory; | |
| 100 }; | |
| 101 | |
| 102 class WorkerThread::WorkerMicrotaskRunner final : public WebThread::TaskObserver { | |
| 55 public: | 103 public: |
| 56 explicit WorkerMicrotaskRunner(WorkerThread* workerThread) | 104 explicit WorkerMicrotaskRunner(WorkerThread* workerThread) |
| 57 : m_workerThread(workerThread) | 105 : m_workerThread(workerThread) |
| 58 { | 106 { |
| 59 } | 107 } |
| 60 | 108 |
| 61 void willProcessTask() override | 109 void willProcessTask() override |
| 62 { | 110 { |
| 63 // No tasks should get executed after we have closed. | 111 // No tasks should get executed after we have closed. |
| 64 DCHECK(!m_workerThread->workerGlobalScope() || !m_workerThread->workerGl obalScope()->isClosing()); | 112 DCHECK(!m_workerThread->workerGlobalScope() || !m_workerThread->workerGl obalScope()->isClosing()); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 93 } | 141 } |
| 94 | 142 |
| 95 static HashSet<WorkerThread*>& workerThreads() | 143 static HashSet<WorkerThread*>& workerThreads() |
| 96 { | 144 { |
| 97 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); | 145 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); |
| 98 return threads; | 146 return threads; |
| 99 } | 147 } |
| 100 | 148 |
| 101 WorkerThread::~WorkerThread() | 149 WorkerThread::~WorkerThread() |
| 102 { | 150 { |
| 151 DCHECK(isMainThread()); | |
| 103 MutexLocker lock(threadSetMutex()); | 152 MutexLocker lock(threadSetMutex()); |
| 104 DCHECK(workerThreads().contains(this)); | 153 DCHECK(workerThreads().contains(this)); |
| 105 workerThreads().remove(this); | 154 workerThreads().remove(this); |
| 155 | |
| 156 // TODO(nhiroki): Record how this thread is terminated (i.e. m_exitCode) | |
| 157 // in UMA. | |
| 158 DCHECK_NE(ExitCode::NotTerminated, m_exitCode); | |
| 106 } | 159 } |
| 107 | 160 |
| 108 void WorkerThread::start(PassOwnPtr<WorkerThreadStartupData> startupData) | 161 void WorkerThread::start(PassOwnPtr<WorkerThreadStartupData> startupData) |
| 109 { | 162 { |
| 110 DCHECK(isMainThread()); | 163 DCHECK(isMainThread()); |
| 111 | 164 |
| 112 if (m_started) | 165 if (m_started) |
| 113 return; | 166 return; |
| 114 | 167 |
| 115 m_started = true; | 168 m_started = true; |
| 116 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::initializeOnWorkerThread, AllowCrossThreadAccess(this), passed (std::move(startupData)))); | 169 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::initializeOnWorkerThread, AllowCrossThreadAccess(this), passed (std::move(startupData)))); |
| 117 } | 170 } |
| 118 | 171 |
| 119 void WorkerThread::terminate() | 172 void WorkerThread::terminate() |
| 120 { | 173 { |
| 121 DCHECK(isMainThread()); | 174 DCHECK(isMainThread()); |
| 122 | 175 terminateInternal(TerminationMode::Graceful); |
| 123 // Prevent the deadlock between GC and an attempt to terminate a thread. | |
| 124 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); | |
| 125 | |
| 126 // Protect against this method, initializeOnWorkerThread() or termination | |
| 127 // via the global scope racing each other. | |
| 128 MutexLocker lock(m_threadStateMutex); | |
| 129 | |
| 130 // If terminate has already been called, just return. | |
| 131 if (m_terminated) | |
| 132 return; | |
| 133 m_terminated = true; | |
| 134 | |
| 135 // Signal the thread to notify that the thread's stopping. | |
| 136 if (m_terminationEvent) | |
| 137 m_terminationEvent->signal(); | |
| 138 | |
| 139 // If the worker thread was never initialized, don't start another | |
| 140 // shutdown, but still wait for the thread to signal when shutdown has | |
| 141 // completed on initializeOnWorkerThread(). | |
| 142 if (!m_workerGlobalScope) | |
| 143 return; | |
| 144 | |
| 145 // Determine if we should terminate the isolate so that the task can | |
| 146 // be handled by thread event loop. If script execution weren't forbidden, | |
| 147 // a while(1) loop in JS could keep the thread alive forever. | |
| 148 // | |
| 149 // (1) |m_readyToShutdown|: It this is set, the worker thread has already | |
| 150 // noticed that the thread is about to be terminated and the worker global | |
| 151 // scope is already disposed, so we don't have to explicitly terminate the | |
| 152 // isolate. | |
| 153 // | |
| 154 // (2) |workerScriptCount() == 1|: If other WorkerGlobalScopes are running | |
| 155 // on the worker thread, we should not terminate the isolate. This condition | |
| 156 // is not entirely correct because other scripts can be being initialized or | |
| 157 // terminated simuletaneously. Though this function itself is protected by a | |
| 158 // mutex, it is possible that |workerScriptCount()| here is not consistent | |
| 159 // with that in |initialize| and |shutdown|. | |
| 160 // | |
| 161 // (3) |m_runningDebuggerTask|: Terminating during debugger task may lead to | |
| 162 // crash due to heavy use of v8 api in debugger. Any debugger task is | |
| 163 // guaranteed to finish, so we can wait for the completion. | |
| 164 bool shouldTerminateIsolate = !m_readyToShutdown && (workerBackingThread().w orkerScriptCount() == 1) && !m_runningDebuggerTask; | |
| 165 | |
| 166 if (shouldTerminateIsolate) { | |
| 167 // TODO(yhirano): TerminateExecution should be called more | |
| 168 // carefully (https://crbug.com/413518). | |
| 169 m_workerGlobalScope->scriptController()->willScheduleExecutionTerminatio n(); | |
| 170 isolate()->TerminateExecution(); | |
| 171 } | |
| 172 | |
| 173 m_inspectorTaskRunner->kill(); | |
| 174 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::prepareForShutdownOnWorkerThread, AllowCrossThreadAccess(this) )); | |
| 175 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::performShutdownOnWorkerThread, AllowCrossThreadAccess(this))); | |
| 176 } | 176 } |
| 177 | 177 |
| 178 void WorkerThread::terminateAndWait() | 178 void WorkerThread::terminateAndWait() |
| 179 { | 179 { |
| 180 DCHECK(isMainThread()); | 180 DCHECK(isMainThread()); |
| 181 terminate(); | 181 |
| 182 // The main thread will be blocked, so asynchronous graceful shutdown does | |
| 183 // not work. | |
| 184 terminateInternal(TerminationMode::Forcible); | |
| 185 | |
| 186 // Terminating the worker thread that hasn't started yet does not run the | |
| 187 // shutdown sequence on the worker thread, so should not wait for the | |
| 188 // shutdown event. | |
| 189 if (m_exitCode == ExitCode::TerminatedBeforeStarting) | |
| 190 return; | |
| 182 m_shutdownEvent->wait(); | 191 m_shutdownEvent->wait(); |
| 183 } | 192 } |
| 184 | 193 |
| 185 void WorkerThread::terminateAndWaitForAllWorkers() | 194 void WorkerThread::terminateAndWaitForAllWorkers() |
| 186 { | 195 { |
| 187 DCHECK(isMainThread()); | 196 DCHECK(isMainThread()); |
| 188 | 197 |
| 189 // Keep this lock to prevent WorkerThread instances from being destroyed. | 198 // Keep this lock to prevent WorkerThread instances from being destroyed. |
| 190 MutexLocker lock(threadSetMutex()); | 199 MutexLocker lock(threadSetMutex()); |
| 191 HashSet<WorkerThread*> threads = workerThreads(); | 200 HashSet<WorkerThread*> threads = workerThreads(); |
| 201 | |
| 202 // The main thread will be blocked, so asynchronous graceful shutdown does | |
| 203 // not work. | |
| 192 for (WorkerThread* thread : threads) | 204 for (WorkerThread* thread : threads) |
| 193 thread->terminate(); | 205 thread->terminateInternal(TerminationMode::Forcible); |
| 194 | 206 |
| 195 for (WorkerThread* thread : threads) | 207 for (WorkerThread* thread : threads) { |
| 208 // Terminating the worker thread that hasn't started yet does not run | |
| 209 // the shutdown sequence on the worker thread, so should not wait for | |
| 210 // the shutdown event. | |
| 211 if (thread->m_exitCode == ExitCode::TerminatedBeforeStarting) | |
| 212 continue; | |
| 196 thread->m_shutdownEvent->wait(); | 213 thread->m_shutdownEvent->wait(); |
| 214 } | |
| 197 } | 215 } |
| 198 | 216 |
| 199 v8::Isolate* WorkerThread::isolate() | 217 v8::Isolate* WorkerThread::isolate() |
| 200 { | 218 { |
| 201 return workerBackingThread().isolate(); | 219 return workerBackingThread().isolate(); |
| 202 } | 220 } |
| 203 | 221 |
| 204 bool WorkerThread::isCurrentThread() | 222 bool WorkerThread::isCurrentThread() |
| 205 { | 223 { |
| 206 return m_started && workerBackingThread().backingThread().isCurrentThread(); | 224 return m_started && workerBackingThread().backingThread().isCurrentThread(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 } | 286 } |
| 269 | 287 |
| 270 PlatformThreadId WorkerThread::platformThreadId() | 288 PlatformThreadId WorkerThread::platformThreadId() |
| 271 { | 289 { |
| 272 if (!m_started) | 290 if (!m_started) |
| 273 return 0; | 291 return 0; |
| 274 return workerBackingThread().backingThread().platformThread().threadId(); | 292 return workerBackingThread().backingThread().platformThread().threadId(); |
| 275 } | 293 } |
| 276 | 294 |
| 277 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work erReportingProxy& workerReportingProxy) | 295 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work erReportingProxy& workerReportingProxy) |
| 278 : m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner())) | 296 : m_forceTerminationDelayInMs(kForceTerminationDelayInMs) |
| 297 , m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner())) | |
| 279 , m_workerLoaderProxy(workerLoaderProxy) | 298 , m_workerLoaderProxy(workerLoaderProxy) |
| 280 , m_workerReportingProxy(workerReportingProxy) | 299 , m_workerReportingProxy(workerReportingProxy) |
| 281 , m_terminationEvent(adoptPtr(new WaitableEvent( | 300 , m_terminationEvent(adoptPtr(new WaitableEvent( |
| 282 WaitableEvent::ResetPolicy::Manual, | 301 WaitableEvent::ResetPolicy::Manual, |
| 283 WaitableEvent::InitialState::NonSignaled))) | 302 WaitableEvent::InitialState::NonSignaled))) |
| 284 , m_shutdownEvent(adoptPtr(new WaitableEvent( | 303 , m_shutdownEvent(adoptPtr(new WaitableEvent( |
| 285 WaitableEvent::ResetPolicy::Manual, | 304 WaitableEvent::ResetPolicy::Manual, |
| 286 WaitableEvent::InitialState::NonSignaled))) | 305 WaitableEvent::InitialState::NonSignaled))) |
| 287 { | 306 { |
| 288 MutexLocker lock(threadSetMutex()); | 307 MutexLocker lock(threadSetMutex()); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 } | 373 } |
| 355 | 374 |
| 356 CachedMetadataHandler* handler = workerGlobalScope()->createWorkerScriptCach edMetadataHandler(scriptURL, cachedMetaData.get()); | 375 CachedMetadataHandler* handler = workerGlobalScope()->createWorkerScriptCach edMetadataHandler(scriptURL, cachedMetaData.get()); |
| 357 bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourc eCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions); | 376 bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourc eCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions); |
| 358 m_workerGlobalScope->didEvaluateWorkerScript(); | 377 m_workerGlobalScope->didEvaluateWorkerScript(); |
| 359 m_workerReportingProxy.didEvaluateWorkerScript(success); | 378 m_workerReportingProxy.didEvaluateWorkerScript(success); |
| 360 | 379 |
| 361 postInitialize(); | 380 postInitialize(); |
| 362 } | 381 } |
| 363 | 382 |
| 383 void WorkerThread::terminateInternal(TerminationMode mode) | |
| 384 { | |
| 385 // Prevent the deadlock between GC and an attempt to terminate a thread. | |
| 386 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); | |
| 387 | |
| 388 // Protect against this method, initializeOnWorkerThread() or termination | |
| 389 // via the global scope racing each other. | |
| 390 MutexLocker lock(m_threadStateMutex); | |
| 391 | |
| 392 // If terminate has already been called. | |
| 393 if (m_terminated) { | |
| 394 // The synchronous forcible termination request should overtake the | |
| 395 // scheduled termination task because the request will block the main | |
| 396 // thread and the scheduled termination task never runs. | |
| 397 if (mode == TerminationMode::Forcible && m_exitCode == ExitCode::NotTerm inated) { | |
| 398 DCHECK(m_scheduledForceTerminationTask); | |
| 399 m_scheduledForceTerminationTask.reset(); | |
| 400 forciblyTerminateIsolate(); | |
| 401 DCHECK_EQ(ExitCode::NotTerminated, m_exitCode); | |
| 402 m_exitCode = ExitCode::SyncForciblyTerminated; | |
| 403 } | |
| 404 return; | |
| 405 } | |
| 406 m_terminated = true; | |
| 407 | |
| 408 // Signal the thread to notify that the thread's stopping. | |
| 409 if (m_terminationEvent) | |
| 410 m_terminationEvent->signal(); | |
| 411 | |
| 412 // If the worker thread was never initialized, don't start another | |
| 413 // shutdown, but still wait for the thread to signal when shutdown has | |
| 414 // completed on initializeOnWorkerThread(). | |
|
kinuko
2016/05/31 10:13:26
Hmm, if we're not calling start() initializeOnWork
kinuko
2016/05/31 10:13:26
The comment looks stale now? (We're no longer wait
nhiroki
2016/06/01 04:16:36
Good point. I'm now thinking that the main thread
| |
| 415 if (!m_workerGlobalScope) { | |
| 416 DCHECK_EQ(ExitCode::NotTerminated, m_exitCode); | |
| 417 m_exitCode = ExitCode::TerminatedBeforeStarting; | |
| 418 return; | |
| 419 } | |
| 420 | |
| 421 // Determine if we should synchronously terminate or schedule to terminate | |
| 422 // the isolate so that the task can be handled by thread event loop. If | |
| 423 // script execution weren't forbidden, a while(1) loop in JS could keep | |
| 424 // the thread alive forever. | |
| 425 // | |
| 426 // (1) |m_readyToShutdown|: It this is set, the worker thread has already | |
| 427 // noticed that the thread is about to be terminated and the worker global | |
| 428 // scope is already disposed, so we don't have to explicitly terminate the | |
| 429 // isolate. | |
| 430 // | |
| 431 // (2) |workerScriptCount() == 1|: If other WorkerGlobalScopes are running | |
| 432 // on the worker thread, we should not terminate the isolate. This condition | |
| 433 // is not entirely correct because other scripts can be being initialized or | |
| 434 // terminated simuletaneously. Though this function itself is protected by a | |
| 435 // mutex, it is possible that |workerScriptCount()| here is not consistent | |
| 436 // with that in |initialize| and |shutdown|. | |
| 437 // | |
| 438 // (3) |m_runningDebuggerTask|: Terminating during debugger task may lead to | |
| 439 // crash due to heavy use of v8 api in debugger. Any debugger task is | |
| 440 // guaranteed to finish, so we can wait for the completion. | |
| 441 bool shouldScheduleToTerminateIsolate = !m_readyToShutdown && (workerBacking Thread().workerScriptCount() == 1) && !m_runningDebuggerTask; | |
| 442 | |
| 443 if (shouldScheduleToTerminateIsolate) { | |
| 444 if (mode == TerminationMode::Forcible) { | |
| 445 forciblyTerminateIsolate(); | |
| 446 DCHECK_EQ(ExitCode::NotTerminated, m_exitCode); | |
| 447 m_exitCode = ExitCode::SyncForciblyTerminated; | |
| 448 } else { | |
| 449 DCHECK_EQ(TerminationMode::Graceful, mode); | |
|
kinuko
2016/05/31 10:13:26
nit: DCHECK(!m_scheduledForceTreminationTask) ?
nhiroki
2016/06/01 04:16:36
Done.
| |
| 450 m_scheduledForceTerminationTask = ForceTerminationTask::create(this) ; | |
| 451 m_scheduledForceTerminationTask->schedule(); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 m_inspectorTaskRunner->kill(); | |
| 456 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::prepareForShutdownOnWorkerThread, AllowCrossThreadAccess(this) )); | |
| 457 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::performShutdownOnWorkerThread, AllowCrossThreadAccess(this))); | |
| 458 } | |
| 459 | |
| 460 void WorkerThread::forciblyTerminateIsolate() | |
| 461 { | |
| 462 DCHECK(m_workerGlobalScope); | |
| 463 m_workerGlobalScope->scriptController()->willScheduleExecutionTermination(); | |
| 464 isolate()->TerminateExecution(); | |
| 465 } | |
| 466 | |
| 364 void WorkerThread::prepareForShutdownOnWorkerThread() | 467 void WorkerThread::prepareForShutdownOnWorkerThread() |
| 365 { | 468 { |
| 366 DCHECK(isCurrentThread()); | 469 DCHECK(isCurrentThread()); |
| 367 { | 470 { |
| 368 MutexLocker lock(m_threadStateMutex); | 471 MutexLocker lock(m_threadStateMutex); |
| 369 if (m_readyToShutdown) | 472 if (m_readyToShutdown) |
| 370 return; | 473 return; |
| 371 m_readyToShutdown = true; | 474 m_readyToShutdown = true; |
| 475 if (m_exitCode == ExitCode::NotTerminated) | |
| 476 m_exitCode = ExitCode::GracefullyTerminated; | |
| 372 } | 477 } |
| 373 | 478 |
| 374 workerReportingProxy().willDestroyWorkerGlobalScope(); | 479 workerReportingProxy().willDestroyWorkerGlobalScope(); |
| 375 InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope()); | 480 InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope()); |
| 376 workerGlobalScope()->dispose(); | 481 workerGlobalScope()->dispose(); |
| 377 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g et()); | 482 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g et()); |
| 378 } | 483 } |
| 379 | 484 |
| 380 void WorkerThread::performShutdownOnWorkerThread() | 485 void WorkerThread::performShutdownOnWorkerThread() |
| 381 { | 486 { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 } | 558 } |
| 454 | 559 |
| 455 void WorkerThread::runDebuggerTaskDontWaitOnWorkerThread() | 560 void WorkerThread::runDebuggerTaskDontWaitOnWorkerThread() |
| 456 { | 561 { |
| 457 DCHECK(isCurrentThread()); | 562 DCHECK(isCurrentThread()); |
| 458 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa sk(InspectorTaskRunner::DontWaitForTask); | 563 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa sk(InspectorTaskRunner::DontWaitForTask); |
| 459 if (task) | 564 if (task) |
| 460 (*task)(); | 565 (*task)(); |
| 461 } | 566 } |
| 462 | 567 |
| 568 WorkerThread::ExitCode WorkerThread::exitCode() | |
| 569 { | |
| 570 MutexLocker lock(m_threadStateMutex); | |
| 571 return m_exitCode; | |
| 572 } | |
| 573 | |
| 463 } // namespace blink | 574 } // namespace blink |
| OLD | NEW |