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 = 2000; // 2 secs | |
57 | |
58 // ForceTerminationTask is used for posting a delayed task to terminate the | |
59 // worker execution from the main thread. This task is expected to run when the | |
60 // shutdown sequence does not start in a certain time period because of an | |
61 // inifite loop in the JS execution context etc. When the shutdown sequence is | |
62 // started before 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->forciblyTerminateExecution(); | |
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); | |
182 m_shutdownEvent->wait(); | 185 m_shutdownEvent->wait(); |
183 } | 186 } |
184 | 187 |
185 void WorkerThread::terminateAndWaitForAllWorkers() | 188 void WorkerThread::terminateAndWaitForAllWorkers() |
186 { | 189 { |
187 DCHECK(isMainThread()); | 190 DCHECK(isMainThread()); |
188 | 191 |
189 // Keep this lock to prevent WorkerThread instances from being destroyed. | 192 // Keep this lock to prevent WorkerThread instances from being destroyed. |
190 MutexLocker lock(threadSetMutex()); | 193 MutexLocker lock(threadSetMutex()); |
191 HashSet<WorkerThread*> threads = workerThreads(); | 194 HashSet<WorkerThread*> threads = workerThreads(); |
195 | |
196 // The main thread will be blocked, so asynchronous graceful shutdown does | |
197 // not work. | |
192 for (WorkerThread* thread : threads) | 198 for (WorkerThread* thread : threads) |
193 thread->terminate(); | 199 thread->terminateInternal(TerminationMode::Forcible); |
194 | 200 |
195 for (WorkerThread* thread : threads) | 201 for (WorkerThread* thread : threads) |
196 thread->m_shutdownEvent->wait(); | 202 thread->m_shutdownEvent->wait(); |
197 } | 203 } |
198 | 204 |
199 v8::Isolate* WorkerThread::isolate() | 205 v8::Isolate* WorkerThread::isolate() |
200 { | 206 { |
201 return workerBackingThread().isolate(); | 207 return workerBackingThread().isolate(); |
202 } | 208 } |
203 | 209 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 } | 274 } |
269 | 275 |
270 PlatformThreadId WorkerThread::platformThreadId() | 276 PlatformThreadId WorkerThread::platformThreadId() |
271 { | 277 { |
272 if (!m_started) | 278 if (!m_started) |
273 return 0; | 279 return 0; |
274 return workerBackingThread().backingThread().platformThread().threadId(); | 280 return workerBackingThread().backingThread().platformThread().threadId(); |
275 } | 281 } |
276 | 282 |
277 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work erReportingProxy& workerReportingProxy) | 283 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work erReportingProxy& workerReportingProxy) |
278 : m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner())) | 284 : m_forceTerminationDelayInMs(kForceTerminationDelayInMs) |
285 , m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner())) | |
279 , m_workerLoaderProxy(workerLoaderProxy) | 286 , m_workerLoaderProxy(workerLoaderProxy) |
280 , m_workerReportingProxy(workerReportingProxy) | 287 , m_workerReportingProxy(workerReportingProxy) |
281 , m_terminationEvent(adoptPtr(new WaitableEvent( | 288 , m_terminationEvent(adoptPtr(new WaitableEvent( |
282 WaitableEvent::ResetPolicy::Manual, | 289 WaitableEvent::ResetPolicy::Manual, |
283 WaitableEvent::InitialState::NonSignaled))) | 290 WaitableEvent::InitialState::NonSignaled))) |
284 , m_shutdownEvent(adoptPtr(new WaitableEvent( | 291 , m_shutdownEvent(adoptPtr(new WaitableEvent( |
285 WaitableEvent::ResetPolicy::Manual, | 292 WaitableEvent::ResetPolicy::Manual, |
286 WaitableEvent::InitialState::NonSignaled))) | 293 WaitableEvent::InitialState::NonSignaled))) |
287 { | 294 { |
288 MutexLocker lock(threadSetMutex()); | 295 MutexLocker lock(threadSetMutex()); |
289 workerThreads().add(this); | 296 workerThreads().add(this); |
290 } | 297 } |
291 | 298 |
292 std::unique_ptr<CrossThreadClosure> WorkerThread::createWorkerThreadTask(std::un ique_ptr<ExecutionContextTask> task, bool isInstrumented) | 299 std::unique_ptr<CrossThreadClosure> WorkerThread::createWorkerThreadTask(std::un ique_ptr<ExecutionContextTask> task, bool isInstrumented) |
293 { | 300 { |
294 if (isInstrumented) | 301 if (isInstrumented) |
295 isInstrumented = !task->taskNameForInstrumentation().isEmpty(); | 302 isInstrumented = !task->taskNameForInstrumentation().isEmpty(); |
296 if (isInstrumented) { | 303 if (isInstrumented) { |
297 DCHECK(isCurrentThread()); | 304 DCHECK(isCurrentThread()); |
298 InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worke r task", task.get()); | 305 InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worke r task", task.get()); |
299 } | 306 } |
300 return threadSafeBind(&WorkerThread::performTaskOnWorkerThread, AllowCrossTh readAccess(this), passed(std::move(task)), isInstrumented); | 307 return threadSafeBind(&WorkerThread::performTaskOnWorkerThread, AllowCrossTh readAccess(this), passed(std::move(task)), isInstrumented); |
301 } | 308 } |
302 | 309 |
310 void WorkerThread::terminateInternal(TerminationMode mode) | |
311 { | |
312 // Prevent the deadlock between GC and an attempt to terminate a thread. | |
313 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); | |
314 | |
315 // Protect against this method, initializeOnWorkerThread() or termination | |
316 // via the global scope racing each other. | |
317 MutexLocker lock(m_threadStateMutex); | |
318 | |
319 // If terminate has already been called. | |
320 if (m_terminated) { | |
321 // The synchronous forcible termination request should overtake the | |
322 // scheduled termination task because the request will block the main | |
323 // thread and the scheduled termination task never runs. | |
324 if (mode == TerminationMode::Forcible && m_exitCode == ExitCode::NotTerm inated) { | |
325 DCHECK(m_scheduledForceTerminationTask); | |
326 m_scheduledForceTerminationTask.reset(); | |
327 forciblyTerminateExecution(); | |
328 DCHECK_EQ(ExitCode::NotTerminated, m_exitCode); | |
329 m_exitCode = ExitCode::SyncForciblyTerminated; | |
330 } | |
331 return; | |
332 } | |
333 m_terminated = true; | |
334 | |
335 // Signal the thread to notify that the thread's stopping. | |
336 if (m_terminationEvent) | |
337 m_terminationEvent->signal(); | |
338 | |
339 // If the worker thread was never initialized, don't start another | |
340 // shutdown, but still wait for the thread to signal when shutdown has | |
341 // completed. | |
342 if (!m_workerGlobalScope) { | |
343 // Post a task to notify the worker reporting proxy of shutdown. When | |
344 // |m_started| is set, it will be notified on initializeOnWorkerThread() | |
345 // instead. | |
346 if (!m_started) | |
kinuko
2016/06/02 02:31:28
I wonder if we should just DCHECK(m_started) in te
nhiroki
2016/06/02 06:20:20
It looks like the worker thread is always supposed
| |
347 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, thre adSafeBind(&WorkerThread::notifyOfShutdownOnWorkerThread, AllowCrossThreadAccess (this))); | |
348 m_readyToShutdown = true; | |
349 DCHECK_EQ(ExitCode::NotTerminated, m_exitCode); | |
350 m_exitCode = ExitCode::TerminatedBeforeStarting; | |
351 return; | |
352 } | |
353 | |
354 // Determine if we should synchronously terminate or schedule to terminate | |
355 // the worker execution so that the task can be handled by thread event | |
356 // loop. If script execution weren't forbidden, a while(1) loop in JS could | |
357 // keep the thread alive forever. | |
358 // | |
359 // (1) |m_readyToShutdown|: It this is set, the worker thread has already | |
360 // noticed that the thread is about to be terminated and the worker global | |
361 // scope is already disposed, so we don't have to explicitly terminate the | |
362 // worker execution. | |
363 // | |
364 // (2) |workerScriptCount() == 1|: If other WorkerGlobalScopes are running | |
365 // on the worker thread, we should not terminate the worker execution. This | |
366 // condition is not entirely correct because other scripts can be being | |
367 // initialized or terminated simuletaneously. Though this function itself is | |
368 // protected by a mutex, it is possible that |workerScriptCount()| here is | |
369 // not consistent with that in |initialize| and |shutdown|. | |
370 // | |
371 // (3) |m_runningDebuggerTask|: Terminating during debugger task may lead to | |
372 // crash due to heavy use of v8 api in debugger. Any debugger task is | |
373 // guaranteed to finish, so we can wait for the completion. | |
374 bool shouldScheduleToTerminateExecution = !m_readyToShutdown && (workerBacki ngThread().workerScriptCount() == 1) && !m_runningDebuggerTask; | |
375 | |
376 if (shouldScheduleToTerminateExecution) { | |
377 if (mode == TerminationMode::Forcible) { | |
378 forciblyTerminateExecution(); | |
379 DCHECK_EQ(ExitCode::NotTerminated, m_exitCode); | |
380 m_exitCode = ExitCode::SyncForciblyTerminated; | |
381 } else { | |
382 DCHECK_EQ(TerminationMode::Graceful, mode); | |
383 DCHECK(!m_scheduledForceTerminationTask); | |
384 m_scheduledForceTerminationTask = ForceTerminationTask::create(this) ; | |
385 m_scheduledForceTerminationTask->schedule(); | |
386 } | |
387 } | |
388 | |
389 m_inspectorTaskRunner->kill(); | |
390 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::prepareForShutdownOnWorkerThread, AllowCrossThreadAccess(this) )); | |
391 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi nd(&WorkerThread::performShutdownOnWorkerThread, AllowCrossThreadAccess(this))); | |
392 } | |
393 | |
394 void WorkerThread::forciblyTerminateExecution() | |
395 { | |
396 DCHECK(m_workerGlobalScope); | |
397 m_workerGlobalScope->scriptController()->willScheduleExecutionTermination(); | |
398 isolate()->TerminateExecution(); | |
399 } | |
400 | |
303 void WorkerThread::initializeOnWorkerThread(PassOwnPtr<WorkerThreadStartupData> startupData) | 401 void WorkerThread::initializeOnWorkerThread(PassOwnPtr<WorkerThreadStartupData> startupData) |
304 { | 402 { |
305 KURL scriptURL = startupData->m_scriptURL; | 403 KURL scriptURL = startupData->m_scriptURL; |
306 String sourceCode = startupData->m_sourceCode; | 404 String sourceCode = startupData->m_sourceCode; |
307 WorkerThreadStartMode startMode = startupData->m_startMode; | 405 WorkerThreadStartMode startMode = startupData->m_startMode; |
308 OwnPtr<Vector<char>> cachedMetaData = std::move(startupData->m_cachedMetaDat a); | 406 OwnPtr<Vector<char>> cachedMetaData = std::move(startupData->m_cachedMetaDat a); |
309 V8CacheOptions v8CacheOptions = startupData->m_v8CacheOptions; | 407 V8CacheOptions v8CacheOptions = startupData->m_v8CacheOptions; |
310 | 408 |
311 { | 409 { |
312 MutexLocker lock(m_threadStateMutex); | 410 MutexLocker lock(m_threadStateMutex); |
313 | 411 |
314 // The worker was terminated before the thread had a chance to run. | 412 // The worker was terminated before the thread had a chance to run. |
315 if (m_terminated) { | 413 if (m_terminated) { |
316 // Notify the proxy that the WorkerGlobalScope has been disposed of. | 414 // In this case the shutdown sequence does not run, so notify of |
317 // This can free this thread object, hence it must not be touched | 415 // thread shutdown here instead. |
318 // afterwards. | 416 notifyOfShutdownOnWorkerThread(); |
319 m_workerReportingProxy.workerThreadTerminated(); | |
320 | |
321 // Notify the main thread that it is safe to deallocate our | |
322 // resources. | |
323 m_shutdownEvent->signal(); | |
324 return; | 417 return; |
325 } | 418 } |
326 | 419 |
327 workerBackingThread().attach(); | 420 workerBackingThread().attach(); |
328 | 421 |
329 if (shouldAttachThreadDebugger()) | 422 if (shouldAttachThreadDebugger()) |
330 V8PerIsolateData::from(isolate())->setThreadDebugger(adoptPtr(new Wo rkerThreadDebugger(this, isolate()))); | 423 V8PerIsolateData::from(isolate())->setThreadDebugger(adoptPtr(new Wo rkerThreadDebugger(this, isolate()))); |
331 m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this)); | 424 m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this)); |
332 workerBackingThread().backingThread().addTaskObserver(m_microtaskRunner. get()); | 425 workerBackingThread().backingThread().addTaskObserver(m_microtaskRunner. get()); |
333 | 426 |
(...skipping 28 matching lines...) Expand all Loading... | |
362 } | 455 } |
363 | 456 |
364 void WorkerThread::prepareForShutdownOnWorkerThread() | 457 void WorkerThread::prepareForShutdownOnWorkerThread() |
365 { | 458 { |
366 DCHECK(isCurrentThread()); | 459 DCHECK(isCurrentThread()); |
367 { | 460 { |
368 MutexLocker lock(m_threadStateMutex); | 461 MutexLocker lock(m_threadStateMutex); |
369 if (m_readyToShutdown) | 462 if (m_readyToShutdown) |
370 return; | 463 return; |
371 m_readyToShutdown = true; | 464 m_readyToShutdown = true; |
465 if (m_exitCode == ExitCode::NotTerminated) | |
466 m_exitCode = ExitCode::GracefullyTerminated; | |
372 } | 467 } |
373 | 468 |
374 workerReportingProxy().willDestroyWorkerGlobalScope(); | 469 workerReportingProxy().willDestroyWorkerGlobalScope(); |
375 InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope()); | 470 InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope()); |
376 workerGlobalScope()->dispose(); | 471 workerGlobalScope()->dispose(); |
377 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g et()); | 472 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g et()); |
378 } | 473 } |
379 | 474 |
380 void WorkerThread::performShutdownOnWorkerThread() | 475 void WorkerThread::performShutdownOnWorkerThread() |
381 { | 476 { |
(...skipping 12 matching lines...) Expand all Loading... | |
394 // is enabled, we detach of the context/global scope, with the final heap | 489 // is enabled, we detach of the context/global scope, with the final heap |
395 // cleanup below sweeping it out. | 490 // cleanup below sweeping it out. |
396 m_workerGlobalScope->notifyContextDestroyed(); | 491 m_workerGlobalScope->notifyContextDestroyed(); |
397 m_workerGlobalScope = nullptr; | 492 m_workerGlobalScope = nullptr; |
398 | 493 |
399 workerBackingThread().detach(); | 494 workerBackingThread().detach(); |
400 // We must not touch workerBackingThread() from now on. | 495 // We must not touch workerBackingThread() from now on. |
401 | 496 |
402 m_microtaskRunner = nullptr; | 497 m_microtaskRunner = nullptr; |
403 | 498 |
404 // Notify the proxy that the WorkerGlobalScope has been disposed of. | 499 notifyOfShutdownOnWorkerThread(); |
405 // This can free this thread object, hence it must not be touched afterwards . | 500 } |
501 | |
502 void WorkerThread::notifyOfShutdownOnWorkerThread() | |
503 { | |
504 #if DCHECK_IS_ON | |
505 { | |
506 MutexLocker lock(m_threadStateMutex); | |
507 DCHECK(m_terminated); | |
508 DCHECK(m_readyToShutdown); | |
509 } | |
510 #endif | |
511 DCHECK(!m_workerGlobalScope); | |
512 | |
513 // Notify the proxy that the WorkerGlobalScope has been disposed of. This | |
514 // can free this thread object, hence it must not be touched afterwards. | |
406 workerReportingProxy().workerThreadTerminated(); | 515 workerReportingProxy().workerThreadTerminated(); |
407 | 516 |
408 m_shutdownEvent->signal(); | 517 m_shutdownEvent->signal(); |
409 } | 518 } |
410 | 519 |
411 void WorkerThread::performTaskOnWorkerThread(std::unique_ptr<ExecutionContextTas k> task, bool isInstrumented) | 520 void WorkerThread::performTaskOnWorkerThread(std::unique_ptr<ExecutionContextTas k> task, bool isInstrumented) |
412 { | 521 { |
413 DCHECK(isCurrentThread()); | 522 DCHECK(isCurrentThread()); |
414 { | 523 { |
415 MutexLocker lock(m_threadStateMutex); | 524 MutexLocker lock(m_threadStateMutex); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
453 } | 562 } |
454 | 563 |
455 void WorkerThread::runDebuggerTaskDontWaitOnWorkerThread() | 564 void WorkerThread::runDebuggerTaskDontWaitOnWorkerThread() |
456 { | 565 { |
457 DCHECK(isCurrentThread()); | 566 DCHECK(isCurrentThread()); |
458 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa sk(InspectorTaskRunner::DontWaitForTask); | 567 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa sk(InspectorTaskRunner::DontWaitForTask); |
459 if (task) | 568 if (task) |
460 (*task)(); | 569 (*task)(); |
461 } | 570 } |
462 | 571 |
572 WorkerThread::ExitCode WorkerThread::getExitCode() | |
573 { | |
574 MutexLocker lock(m_threadStateMutex); | |
575 return m_exitCode; | |
576 } | |
577 | |
463 } // namespace blink | 578 } // namespace blink |
OLD | NEW |