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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 Microtask::performCheckpoint(m_workerThread->isolate()); | 69 Microtask::performCheckpoint(m_workerThread->isolate()); |
70 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()
) { | 70 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()
) { |
71 if (WorkerOrWorkletScriptController* scriptController = globalScope-
>scriptController()) | 71 if (WorkerOrWorkletScriptController* scriptController = globalScope-
>scriptController()) |
72 scriptController->getRejectedPromises()->processQueue(); | 72 scriptController->getRejectedPromises()->processQueue(); |
73 if (globalScope->isClosing()) { | 73 if (globalScope->isClosing()) { |
74 // |m_workerThread| will eventually be requested to terminate. | 74 // |m_workerThread| will eventually be requested to terminate. |
75 m_workerThread->workerReportingProxy().workerGlobalScopeClosed()
; | 75 m_workerThread->workerReportingProxy().workerGlobalScopeClosed()
; |
76 | 76 |
77 // Dispose WorkerGlobalScope to stop associated ActiveDOMObjects | 77 // Dispose WorkerGlobalScope to stop associated ActiveDOMObjects |
78 // and close the event queue. | 78 // and close the event queue. |
79 m_workerThread->prepareForShutdown(); | 79 m_workerThread->prepareForShutdownOnWorkerThread(); |
80 } | 80 } |
81 } | 81 } |
82 } | 82 } |
83 | 83 |
84 private: | 84 private: |
85 // Thread owns the microtask runner; reference remains | 85 // Thread owns the microtask runner; reference remains |
86 // valid for the lifetime of this object. | 86 // valid for the lifetime of this object. |
87 WorkerThread* m_workerThread; | 87 WorkerThread* m_workerThread; |
88 }; | 88 }; |
89 | 89 |
90 static Mutex& threadSetMutex() | 90 static Mutex& threadSetMutex() |
91 { | 91 { |
92 DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, new Mutex); | 92 DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, new Mutex); |
93 return mutex; | 93 return mutex; |
94 } | 94 } |
95 | 95 |
96 static HashSet<WorkerThread*>& workerThreads() | 96 static HashSet<WorkerThread*>& workerThreads() |
97 { | 97 { |
98 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); | 98 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); |
99 return threads; | 99 return threads; |
100 } | 100 } |
101 | 101 |
| 102 WorkerThread::~WorkerThread() |
| 103 { |
| 104 MutexLocker lock(threadSetMutex()); |
| 105 DCHECK(workerThreads().contains(this)); |
| 106 workerThreads().remove(this); |
| 107 } |
| 108 |
| 109 void WorkerThread::start(PassOwnPtr<WorkerThreadStartupData> startupData) |
| 110 { |
| 111 DCHECK(isMainThread()); |
| 112 |
| 113 if (m_started) |
| 114 return; |
| 115 |
| 116 m_started = true; |
| 117 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::initializeOnWorkerThread, AllowCrossThreadAccess(this), passed
(std::move(startupData)))); |
| 118 } |
| 119 |
| 120 void WorkerThread::terminate() |
| 121 { |
| 122 DCHECK(isMainThread()); |
| 123 |
| 124 // Prevent the deadlock between GC and an attempt to terminate a thread. |
| 125 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); |
| 126 |
| 127 // Protect against this method, initializeOnWorkerThread() or termination |
| 128 // via the global scope racing each other. |
| 129 MutexLocker lock(m_threadStateMutex); |
| 130 |
| 131 // If terminate has already been called, just return. |
| 132 if (m_terminated) |
| 133 return; |
| 134 m_terminated = true; |
| 135 |
| 136 // Signal the thread to notify that the thread's stopping. |
| 137 if (m_terminationEvent) |
| 138 m_terminationEvent->signal(); |
| 139 |
| 140 // If the worker thread was never initialized, don't start another |
| 141 // shutdown, but still wait for the thread to signal when shutdown has |
| 142 // completed on initializeOnWorkerThread(). |
| 143 if (!m_workerGlobalScope) |
| 144 return; |
| 145 |
| 146 if (!m_readyToShutdown) { |
| 147 // Ensure that tasks are being handled by thread event loop. If script |
| 148 // execution weren't forbidden, a while(1) loop in JS could keep the |
| 149 // thread alive forever. |
| 150 // If |m_readyToShutdown| is set, the worker thread has already noticed |
| 151 // that the thread is about to be terminated and the worker global scope |
| 152 // is already disposed, so we don't have to explicitly terminate the |
| 153 // execution. |
| 154 m_workerGlobalScope->scriptController()->willScheduleExecutionTerminatio
n(); |
| 155 |
| 156 // This condition is not entirely correct because other scripts can |
| 157 // be being initialized or terminated simuletaneously. Though this |
| 158 // function itself is protected by a mutex, it is possible that |
| 159 // |workerScriptCount()| here is not consistent with that in |
| 160 // |initialize| and |shutdown|. |
| 161 if (workerBackingThread().workerScriptCount() == 1) { |
| 162 if (m_runningDebuggerTask) { |
| 163 // Terminating during debugger task may lead to crash due to |
| 164 // heavy use of v8 api in debugger. Any debugger task is |
| 165 // guaranteed to finish, so we can postpone termination after |
| 166 // task has finished. |
| 167 // Note: m_runningDebuggerTask and m_shouldTerminateV8Execution |
| 168 // access must be guarded by the lock. |
| 169 m_shouldTerminateV8Execution = true; |
| 170 } else { |
| 171 // TODO(yhirano): TerminateExecution should be called more |
| 172 // carefully (https://crbug.com/413518). |
| 173 isolate()->TerminateExecution(); |
| 174 } |
| 175 } |
| 176 } |
| 177 |
| 178 m_inspectorTaskRunner->kill(); |
| 179 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::prepareForShutdownOnWorkerThread, AllowCrossThreadAccess(this)
)); |
| 180 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::performShutdownOnWorkerThread, AllowCrossThreadAccess(this))); |
| 181 } |
| 182 |
| 183 void WorkerThread::terminateAndWait() |
| 184 { |
| 185 DCHECK(isMainThread()); |
| 186 terminate(); |
| 187 m_shutdownEvent->wait(); |
| 188 } |
| 189 |
| 190 void WorkerThread::terminateAndWaitForAllWorkers() |
| 191 { |
| 192 DCHECK(isMainThread()); |
| 193 |
| 194 // Keep this lock to prevent WorkerThread instances from being destroyed. |
| 195 MutexLocker lock(threadSetMutex()); |
| 196 HashSet<WorkerThread*> threads = workerThreads(); |
| 197 for (WorkerThread* thread : threads) |
| 198 thread->terminate(); |
| 199 |
| 200 for (WorkerThread* thread : threads) |
| 201 thread->m_shutdownEvent->wait(); |
| 202 } |
| 203 |
| 204 v8::Isolate* WorkerThread::isolate() |
| 205 { |
| 206 return workerBackingThread().isolate(); |
| 207 } |
| 208 |
| 209 bool WorkerThread::isCurrentThread() |
| 210 { |
| 211 return m_started && workerBackingThread().backingThread().isCurrentThread(); |
| 212 } |
| 213 |
| 214 void WorkerThread::postTask(const WebTraceLocation& location, std::unique_ptr<Ex
ecutionContextTask> task) |
| 215 { |
| 216 workerBackingThread().backingThread().postTask(location, createWorkerThreadT
ask(std::move(task), true)); |
| 217 } |
| 218 |
| 219 void WorkerThread::appendDebuggerTask(std::unique_ptr<CrossThreadClosure> task) |
| 220 { |
| 221 { |
| 222 MutexLocker lock(m_threadStateMutex); |
| 223 if (m_readyToShutdown) |
| 224 return; |
| 225 } |
| 226 m_inspectorTaskRunner->appendTask(threadSafeBind(&WorkerThread::runDebuggerT
askOnWorkerThread, AllowCrossThreadAccess(this), passed(std::move(task)))); |
| 227 { |
| 228 MutexLocker lock(m_threadStateMutex); |
| 229 if (isolate()) |
| 230 m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate()); |
| 231 } |
| 232 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::runDebuggerTaskDontWaitOnWorkerThread, AllowCrossThreadAccess(
this))); |
| 233 } |
| 234 |
| 235 void WorkerThread::startRunningDebuggerTasksOnPause() |
| 236 { |
| 237 m_pausedInDebugger = true; |
| 238 ThreadDebugger::idleStarted(isolate()); |
| 239 std::unique_ptr<CrossThreadClosure> task; |
| 240 do { |
| 241 { |
| 242 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); |
| 243 task = m_inspectorTaskRunner->takeNextTask(InspectorTaskRunner::Wait
ForTask); |
| 244 } |
| 245 if (task) |
| 246 (*task)(); |
| 247 // Keep waiting until execution is resumed. |
| 248 } while (task && m_pausedInDebugger); |
| 249 ThreadDebugger::idleFinished(isolate()); |
| 250 } |
| 251 |
| 252 void WorkerThread::stopRunningDebuggerTasksOnPause() |
| 253 { |
| 254 m_pausedInDebugger = false; |
| 255 } |
| 256 |
| 257 WorkerGlobalScope* WorkerThread::workerGlobalScope() |
| 258 { |
| 259 DCHECK(isCurrentThread()); |
| 260 return m_workerGlobalScope.get(); |
| 261 } |
| 262 |
| 263 bool WorkerThread::terminated() |
| 264 { |
| 265 MutexLocker lock(m_threadStateMutex); |
| 266 return m_terminated; |
| 267 } |
| 268 |
102 unsigned WorkerThread::workerThreadCount() | 269 unsigned WorkerThread::workerThreadCount() |
103 { | 270 { |
104 MutexLocker lock(threadSetMutex()); | 271 MutexLocker lock(threadSetMutex()); |
105 return workerThreads().size(); | 272 return workerThreads().size(); |
106 } | 273 } |
107 | 274 |
108 void WorkerThread::performTask(std::unique_ptr<ExecutionContextTask> task, bool
isInstrumented) | 275 PlatformThreadId WorkerThread::platformThreadId() |
109 { | 276 { |
110 DCHECK(isCurrentThread()); | 277 if (!m_started) |
111 { | 278 return 0; |
112 MutexLocker lock(m_threadStateMutex); | 279 return workerBackingThread().backingThread().platformThread().threadId(); |
113 if (m_readyToShutdown) | |
114 return; | |
115 } | |
116 | |
117 WorkerGlobalScope* globalScope = workerGlobalScope(); | |
118 // If the thread is terminated before it had a chance initialize (see | |
119 // WorkerThread::Initialize()), we mustn't run any of the posted tasks. | |
120 if (!globalScope) { | |
121 DCHECK(terminated()); | |
122 return; | |
123 } | |
124 | |
125 InspectorInstrumentation::AsyncTask asyncTask(globalScope, task.get(), isIns
trumented); | |
126 task->performTask(globalScope); | |
127 } | |
128 | |
129 std::unique_ptr<CrossThreadClosure> WorkerThread::createWorkerThreadTask(std::un
ique_ptr<ExecutionContextTask> task, bool isInstrumented) | |
130 { | |
131 if (isInstrumented) | |
132 isInstrumented = !task->taskNameForInstrumentation().isEmpty(); | |
133 if (isInstrumented) { | |
134 DCHECK(isCurrentThread()); | |
135 InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worke
r task", task.get()); | |
136 } | |
137 return threadSafeBind(&WorkerThread::performTask, AllowCrossThreadAccess(thi
s), passed(std::move(task)), isInstrumented); | |
138 } | 280 } |
139 | 281 |
140 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work
erReportingProxy& workerReportingProxy) | 282 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work
erReportingProxy& workerReportingProxy) |
141 : m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner())) | 283 : m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner())) |
142 , m_workerLoaderProxy(workerLoaderProxy) | 284 , m_workerLoaderProxy(workerLoaderProxy) |
143 , m_workerReportingProxy(workerReportingProxy) | 285 , m_workerReportingProxy(workerReportingProxy) |
144 , m_terminationEvent(adoptPtr(new WaitableEvent( | 286 , m_terminationEvent(adoptPtr(new WaitableEvent( |
145 WaitableEvent::ResetPolicy::Manual, | 287 WaitableEvent::ResetPolicy::Manual, |
146 WaitableEvent::InitialState::NonSignaled))) | 288 WaitableEvent::InitialState::NonSignaled))) |
147 , m_shutdownEvent(adoptPtr(new WaitableEvent( | 289 , m_shutdownEvent(adoptPtr(new WaitableEvent( |
148 WaitableEvent::ResetPolicy::Manual, | 290 WaitableEvent::ResetPolicy::Manual, |
149 WaitableEvent::InitialState::NonSignaled))) | 291 WaitableEvent::InitialState::NonSignaled))) |
150 { | 292 { |
151 MutexLocker lock(threadSetMutex()); | 293 MutexLocker lock(threadSetMutex()); |
152 workerThreads().add(this); | 294 workerThreads().add(this); |
153 } | 295 } |
154 | 296 |
155 WorkerThread::~WorkerThread() | 297 std::unique_ptr<CrossThreadClosure> WorkerThread::createWorkerThreadTask(std::un
ique_ptr<ExecutionContextTask> task, bool isInstrumented) |
156 { | 298 { |
157 MutexLocker lock(threadSetMutex()); | 299 if (isInstrumented) |
158 DCHECK(workerThreads().contains(this)); | 300 isInstrumented = !task->taskNameForInstrumentation().isEmpty(); |
159 workerThreads().remove(this); | 301 if (isInstrumented) { |
| 302 DCHECK(isCurrentThread()); |
| 303 InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worke
r task", task.get()); |
| 304 } |
| 305 return threadSafeBind(&WorkerThread::performTaskOnWorkerThread, AllowCrossTh
readAccess(this), passed(std::move(task)), isInstrumented); |
160 } | 306 } |
161 | 307 |
162 void WorkerThread::start(PassOwnPtr<WorkerThreadStartupData> startupData) | 308 void WorkerThread::initializeOnWorkerThread(PassOwnPtr<WorkerThreadStartupData>
startupData) |
163 { | |
164 DCHECK(isMainThread()); | |
165 | |
166 if (m_started) | |
167 return; | |
168 | |
169 m_started = true; | |
170 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::initialize, AllowCrossThreadAccess(this), passed(std::move(sta
rtupData)))); | |
171 } | |
172 | |
173 PlatformThreadId WorkerThread::platformThreadId() | |
174 { | |
175 if (!m_started) | |
176 return 0; | |
177 return workerBackingThread().backingThread().platformThread().threadId(); | |
178 } | |
179 | |
180 void WorkerThread::initialize(PassOwnPtr<WorkerThreadStartupData> startupData) | |
181 { | 309 { |
182 KURL scriptURL = startupData->m_scriptURL; | 310 KURL scriptURL = startupData->m_scriptURL; |
183 String sourceCode = startupData->m_sourceCode; | 311 String sourceCode = startupData->m_sourceCode; |
184 WorkerThreadStartMode startMode = startupData->m_startMode; | 312 WorkerThreadStartMode startMode = startupData->m_startMode; |
185 OwnPtr<Vector<char>> cachedMetaData = std::move(startupData->m_cachedMetaDat
a); | 313 OwnPtr<Vector<char>> cachedMetaData = std::move(startupData->m_cachedMetaDat
a); |
186 V8CacheOptions v8CacheOptions = startupData->m_v8CacheOptions; | 314 V8CacheOptions v8CacheOptions = startupData->m_v8CacheOptions; |
187 | 315 |
188 { | 316 { |
189 MutexLocker lock(m_threadStateMutex); | 317 MutexLocker lock(m_threadStateMutex); |
190 | 318 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 } | 359 } |
232 | 360 |
233 CachedMetadataHandler* handler = workerGlobalScope()->createWorkerScriptCach
edMetadataHandler(scriptURL, cachedMetaData.get()); | 361 CachedMetadataHandler* handler = workerGlobalScope()->createWorkerScriptCach
edMetadataHandler(scriptURL, cachedMetaData.get()); |
234 bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourc
eCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions); | 362 bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourc
eCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions); |
235 m_workerGlobalScope->didEvaluateWorkerScript(); | 363 m_workerGlobalScope->didEvaluateWorkerScript(); |
236 m_workerReportingProxy.didEvaluateWorkerScript(success); | 364 m_workerReportingProxy.didEvaluateWorkerScript(success); |
237 | 365 |
238 postInitialize(); | 366 postInitialize(); |
239 } | 367 } |
240 | 368 |
241 void WorkerThread::prepareForShutdown() | 369 void WorkerThread::prepareForShutdownOnWorkerThread() |
242 { | 370 { |
243 DCHECK(isCurrentThread()); | 371 DCHECK(isCurrentThread()); |
244 { | 372 { |
245 MutexLocker lock(m_threadStateMutex); | 373 MutexLocker lock(m_threadStateMutex); |
246 if (m_readyToShutdown) | 374 if (m_readyToShutdown) |
247 return; | 375 return; |
248 m_readyToShutdown = true; | 376 m_readyToShutdown = true; |
249 } | 377 } |
250 | 378 |
251 workerReportingProxy().willDestroyWorkerGlobalScope(); | 379 workerReportingProxy().willDestroyWorkerGlobalScope(); |
252 InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope()); | 380 InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope()); |
253 workerGlobalScope()->dispose(); | 381 workerGlobalScope()->dispose(); |
254 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g
et()); | 382 workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.g
et()); |
255 } | 383 } |
256 | 384 |
257 void WorkerThread::performShutdown() | 385 void WorkerThread::performShutdownOnWorkerThread() |
258 { | 386 { |
259 DCHECK(isCurrentThread()); | 387 DCHECK(isCurrentThread()); |
260 #if DCHECK_IS_ON | 388 #if DCHECK_IS_ON |
261 { | 389 { |
262 MutexLocker lock(m_threadStateMutex); | 390 MutexLocker lock(m_threadStateMutex); |
263 DCHECK(m_terminated); | 391 DCHECK(m_terminated); |
264 DCHECK(m_readyToShutdown); | 392 DCHECK(m_readyToShutdown); |
265 } | 393 } |
266 #endif | 394 #endif |
267 | 395 |
(...skipping 10 matching lines...) Expand all Loading... |
278 | 406 |
279 m_microtaskRunner = nullptr; | 407 m_microtaskRunner = nullptr; |
280 | 408 |
281 // Notify the proxy that the WorkerGlobalScope has been disposed of. | 409 // Notify the proxy that the WorkerGlobalScope has been disposed of. |
282 // This can free this thread object, hence it must not be touched afterwards
. | 410 // This can free this thread object, hence it must not be touched afterwards
. |
283 workerReportingProxy().workerThreadTerminated(); | 411 workerReportingProxy().workerThreadTerminated(); |
284 | 412 |
285 m_shutdownEvent->signal(); | 413 m_shutdownEvent->signal(); |
286 } | 414 } |
287 | 415 |
288 void WorkerThread::terminate() | 416 void WorkerThread::performTaskOnWorkerThread(std::unique_ptr<ExecutionContextTas
k> task, bool isInstrumented) |
289 { | |
290 DCHECK(isMainThread()); | |
291 | |
292 // Prevent the deadlock between GC and an attempt to terminate a thread. | |
293 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); | |
294 | |
295 // Protect against this method, initialize() or termination via the global | |
296 // scope racing each other. | |
297 MutexLocker lock(m_threadStateMutex); | |
298 | |
299 // If terminate has already been called, just return. | |
300 if (m_terminated) | |
301 return; | |
302 m_terminated = true; | |
303 | |
304 // Signal the thread to notify that the thread's stopping. | |
305 if (m_terminationEvent) | |
306 m_terminationEvent->signal(); | |
307 | |
308 // If the worker thread was never initialized, don't start another | |
309 // shutdown, but still wait for the thread to signal when shutdown has | |
310 // completed on initialize(). | |
311 if (!m_workerGlobalScope) | |
312 return; | |
313 | |
314 if (!m_readyToShutdown) { | |
315 // Ensure that tasks are being handled by thread event loop. If script | |
316 // execution weren't forbidden, a while(1) loop in JS could keep the | |
317 // thread alive forever. | |
318 // If |m_readyToShutdown| is set, the worker thread has already noticed | |
319 // that the thread is about to be terminated and the worker global scope | |
320 // is already disposed, so we don't have to explicitly terminate the | |
321 // execution. | |
322 m_workerGlobalScope->scriptController()->willScheduleExecutionTerminatio
n(); | |
323 | |
324 // This condition is not entirely correct because other scripts can | |
325 // be being initialized or terminated simuletaneously. Though this | |
326 // function itself is protected by a mutex, it is possible that | |
327 // |workerScriptCount()| here is not consistent with that in | |
328 // |initialize| and |shutdown|. | |
329 if (workerBackingThread().workerScriptCount() == 1) { | |
330 if (m_runningDebuggerTask) { | |
331 // Terminating during debugger task may lead to crash due to | |
332 // heavy use of v8 api in debugger. Any debugger task is | |
333 // guaranteed to finish, so we can postpone termination after | |
334 // task has finished. | |
335 // Note: m_runningDebuggerTask and m_shouldTerminateV8Execution | |
336 // access must be guarded by the lock. | |
337 m_shouldTerminateV8Execution = true; | |
338 } else { | |
339 // TODO(yhirano): TerminateExecution should be called more | |
340 // carefully (https://crbug.com/413518). | |
341 isolate()->TerminateExecution(); | |
342 } | |
343 } | |
344 } | |
345 | |
346 m_inspectorTaskRunner->kill(); | |
347 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::prepareForShutdown, AllowCrossThreadAccess(this))); | |
348 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::performShutdown, AllowCrossThreadAccess(this))); | |
349 } | |
350 | |
351 void WorkerThread::terminateAndWait() | |
352 { | |
353 DCHECK(isMainThread()); | |
354 terminate(); | |
355 m_shutdownEvent->wait(); | |
356 } | |
357 | |
358 void WorkerThread::terminateAndWaitForAllWorkers() | |
359 { | |
360 DCHECK(isMainThread()); | |
361 | |
362 // Keep this lock to prevent WorkerThread instances from being destroyed. | |
363 MutexLocker lock(threadSetMutex()); | |
364 HashSet<WorkerThread*> threads = workerThreads(); | |
365 for (WorkerThread* thread : threads) | |
366 thread->terminate(); | |
367 | |
368 for (WorkerThread* thread : threads) | |
369 thread->m_shutdownEvent->wait(); | |
370 } | |
371 | |
372 WorkerGlobalScope* WorkerThread::workerGlobalScope() | |
373 { | 417 { |
374 DCHECK(isCurrentThread()); | 418 DCHECK(isCurrentThread()); |
375 return m_workerGlobalScope.get(); | |
376 } | |
377 | |
378 bool WorkerThread::terminated() | |
379 { | |
380 MutexLocker lock(m_threadStateMutex); | |
381 return m_terminated; | |
382 } | |
383 | |
384 v8::Isolate* WorkerThread::isolate() | |
385 { | |
386 return workerBackingThread().isolate(); | |
387 } | |
388 | |
389 bool WorkerThread::isCurrentThread() | |
390 { | |
391 return m_started && workerBackingThread().backingThread().isCurrentThread(); | |
392 } | |
393 | |
394 void WorkerThread::postTask(const WebTraceLocation& location, std::unique_ptr<Ex
ecutionContextTask> task) | |
395 { | |
396 workerBackingThread().backingThread().postTask(location, createWorkerThreadT
ask(std::move(task), true)); | |
397 } | |
398 | |
399 void WorkerThread::runDebuggerTaskDontWait() | |
400 { | |
401 DCHECK(isCurrentThread()); | |
402 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa
sk(InspectorTaskRunner::DontWaitForTask); | |
403 if (task) | |
404 (*task)(); | |
405 } | |
406 | |
407 void WorkerThread::appendDebuggerTask(std::unique_ptr<CrossThreadClosure> task) | |
408 { | |
409 { | 419 { |
410 MutexLocker lock(m_threadStateMutex); | 420 MutexLocker lock(m_threadStateMutex); |
411 if (m_readyToShutdown) | 421 if (m_readyToShutdown) |
412 return; | 422 return; |
413 } | 423 } |
414 m_inspectorTaskRunner->appendTask(threadSafeBind(&WorkerThread::runDebuggerT
ask, AllowCrossThreadAccess(this), passed(std::move(task)))); | 424 |
415 { | 425 WorkerGlobalScope* globalScope = workerGlobalScope(); |
416 MutexLocker lock(m_threadStateMutex); | 426 // If the thread is terminated before it had a chance initialize (see |
417 if (isolate()) | 427 // WorkerThread::Initialize()), we mustn't run any of the posted tasks. |
418 m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate()); | 428 if (!globalScope) { |
| 429 DCHECK(terminated()); |
| 430 return; |
419 } | 431 } |
420 workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBi
nd(&WorkerThread::runDebuggerTaskDontWait, AllowCrossThreadAccess(this))); | 432 |
| 433 InspectorInstrumentation::AsyncTask asyncTask(globalScope, task.get(), isIns
trumented); |
| 434 task->performTask(globalScope); |
421 } | 435 } |
422 | 436 |
423 void WorkerThread::runDebuggerTask(std::unique_ptr<CrossThreadClosure> task) | 437 void WorkerThread::runDebuggerTaskOnWorkerThread(std::unique_ptr<CrossThreadClos
ure> task) |
424 { | 438 { |
425 DCHECK(isCurrentThread()); | 439 DCHECK(isCurrentThread()); |
426 InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get()
); | 440 InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get()
); |
427 { | 441 { |
428 MutexLocker lock(m_threadStateMutex); | 442 MutexLocker lock(m_threadStateMutex); |
429 m_runningDebuggerTask = true; | 443 m_runningDebuggerTask = true; |
430 } | 444 } |
431 ThreadDebugger::idleFinished(isolate()); | 445 ThreadDebugger::idleFinished(isolate()); |
432 (*task)(); | 446 (*task)(); |
433 ThreadDebugger::idleStarted(isolate()); | 447 ThreadDebugger::idleStarted(isolate()); |
434 { | 448 { |
435 MutexLocker lock(m_threadStateMutex); | 449 MutexLocker lock(m_threadStateMutex); |
436 m_runningDebuggerTask = false; | 450 m_runningDebuggerTask = false; |
437 if (m_shouldTerminateV8Execution) { | 451 if (m_shouldTerminateV8Execution) { |
438 m_shouldTerminateV8Execution = false; | 452 m_shouldTerminateV8Execution = false; |
439 isolate()->TerminateExecution(); | 453 isolate()->TerminateExecution(); |
440 } | 454 } |
441 } | 455 } |
442 } | 456 } |
443 | 457 |
444 void WorkerThread::startRunningDebuggerTasksOnPause() | 458 void WorkerThread::runDebuggerTaskDontWaitOnWorkerThread() |
445 { | 459 { |
446 m_pausedInDebugger = true; | 460 DCHECK(isCurrentThread()); |
447 ThreadDebugger::idleStarted(isolate()); | 461 std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTa
sk(InspectorTaskRunner::DontWaitForTask); |
448 std::unique_ptr<CrossThreadClosure> task; | 462 if (task) |
449 do { | 463 (*task)(); |
450 { | |
451 SafePointScope safePointScope(BlinkGC::HeapPointersOnStack); | |
452 task = m_inspectorTaskRunner->takeNextTask(InspectorTaskRunner::Wait
ForTask); | |
453 } | |
454 if (task) | |
455 (*task)(); | |
456 // Keep waiting until execution is resumed. | |
457 } while (task && m_pausedInDebugger); | |
458 ThreadDebugger::idleFinished(isolate()); | |
459 } | |
460 | |
461 void WorkerThread::stopRunningDebuggerTasksOnPause() | |
462 { | |
463 m_pausedInDebugger = false; | |
464 } | 464 } |
465 | 465 |
466 } // namespace blink | 466 } // namespace blink |
OLD | NEW |