| 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 20 matching lines...) Expand all  Loading... | 
| 31 #include "bindings/core/v8/ScriptSourceCode.h" | 31 #include "bindings/core/v8/ScriptSourceCode.h" | 
| 32 #include "bindings/core/v8/V8GCController.h" | 32 #include "bindings/core/v8/V8GCController.h" | 
| 33 #include "bindings/core/v8/V8Initializer.h" | 33 #include "bindings/core/v8/V8Initializer.h" | 
| 34 #include "core/dom/Microtask.h" | 34 #include "core/dom/Microtask.h" | 
| 35 #include "core/inspector/InspectorInstrumentation.h" | 35 #include "core/inspector/InspectorInstrumentation.h" | 
| 36 #include "core/inspector/WorkerInspectorController.h" | 36 #include "core/inspector/WorkerInspectorController.h" | 
| 37 #include "core/workers/DedicatedWorkerGlobalScope.h" | 37 #include "core/workers/DedicatedWorkerGlobalScope.h" | 
| 38 #include "core/workers/WorkerClients.h" | 38 #include "core/workers/WorkerClients.h" | 
| 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" |  | 
| 42 #include "platform/Task.h" | 41 #include "platform/Task.h" | 
| 43 #include "platform/ThreadSafeFunctional.h" | 42 #include "platform/ThreadSafeFunctional.h" | 
| 44 #include "platform/ThreadTimers.h" |  | 
| 45 #include "platform/heap/SafePoint.h" | 43 #include "platform/heap/SafePoint.h" | 
| 46 #include "platform/heap/ThreadState.h" | 44 #include "platform/heap/ThreadState.h" | 
| 47 #include "platform/weborigin/KURL.h" | 45 #include "platform/weborigin/KURL.h" | 
| 48 #include "public/platform/Platform.h" | 46 #include "public/platform/Platform.h" | 
|  | 47 #include "public/platform/WebScheduler.h" | 
| 49 #include "public/platform/WebThread.h" | 48 #include "public/platform/WebThread.h" | 
| 50 #include "public/platform/WebWaitableEvent.h" | 49 #include "public/platform/WebWaitableEvent.h" | 
| 51 #include "wtf/Noncopyable.h" | 50 #include "wtf/Noncopyable.h" | 
| 52 #include "wtf/WeakPtr.h" | 51 #include "wtf/WeakPtr.h" | 
| 53 #include "wtf/text/WTFString.h" | 52 #include "wtf/text/WTFString.h" | 
| 54 | 53 | 
| 55 namespace blink { | 54 namespace blink { | 
| 56 | 55 | 
| 57 namespace { | 56 namespace { | 
| 58 const int64_t kShortIdleHandlerDelayMs = 1000; | 57 const double kLongIdleHandlerDelaySecs = 1.0; | 
| 59 const int64_t kLongIdleHandlerDelayMs = 10*1000; |  | 
| 60 | 58 | 
| 61 class MicrotaskRunner : public WebThread::TaskObserver { | 59 class MicrotaskRunner : public WebThread::TaskObserver { | 
| 62 public: | 60 public: | 
| 63     explicit MicrotaskRunner(WorkerThread* workerThread) | 61     explicit MicrotaskRunner(WorkerThread* workerThread) | 
| 64         : m_workerThread(workerThread) | 62         : m_workerThread(workerThread) | 
| 65     { | 63     { | 
| 66     } | 64     } | 
| 67 | 65 | 
| 68     virtual void willProcessTask() override { } | 66     virtual void willProcessTask() override { } | 
| 69     virtual void didProcessTask() override | 67     virtual void didProcessTask() override | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 94     DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); | 92     DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); | 
| 95     return threads; | 93     return threads; | 
| 96 } | 94 } | 
| 97 | 95 | 
| 98 unsigned WorkerThread::workerThreadCount() | 96 unsigned WorkerThread::workerThreadCount() | 
| 99 { | 97 { | 
| 100     MutexLocker lock(threadSetMutex()); | 98     MutexLocker lock(threadSetMutex()); | 
| 101     return workerThreads().size(); | 99     return workerThreads().size(); | 
| 102 } | 100 } | 
| 103 | 101 | 
| 104 class WorkerThreadCancelableTask final : public ExecutionContextTask { |  | 
| 105     WTF_MAKE_NONCOPYABLE(WorkerThreadCancelableTask); WTF_MAKE_FAST_ALLOCATED(Wo
     rkerThreadCancelableTask); |  | 
| 106 public: |  | 
| 107     static PassOwnPtr<WorkerThreadCancelableTask> create(PassOwnPtr<Closure> clo
     sure) |  | 
| 108     { |  | 
| 109         return adoptPtr(new WorkerThreadCancelableTask(closure)); |  | 
| 110     } |  | 
| 111 |  | 
| 112     virtual ~WorkerThreadCancelableTask() { } |  | 
| 113 |  | 
| 114     virtual void performTask(ExecutionContext*) override |  | 
| 115     { |  | 
| 116         if (!m_taskCanceled) |  | 
| 117             (*m_closure)(); |  | 
| 118     } |  | 
| 119 |  | 
| 120     WeakPtr<WorkerThreadCancelableTask> createWeakPtr() { return m_weakFactory.c
     reateWeakPtr(); } |  | 
| 121     void cancelTask() { m_taskCanceled = true; } |  | 
| 122 |  | 
| 123 private: |  | 
| 124     explicit WorkerThreadCancelableTask(PassOwnPtr<Closure> closure) |  | 
| 125         : m_closure(closure) |  | 
| 126         , m_weakFactory(this) |  | 
| 127         , m_taskCanceled(false) |  | 
| 128     { } |  | 
| 129 |  | 
| 130     OwnPtr<Closure> m_closure; |  | 
| 131     WeakPtrFactory<WorkerThreadCancelableTask> m_weakFactory; |  | 
| 132     bool m_taskCanceled; |  | 
| 133 }; |  | 
| 134 |  | 
| 135 class WorkerSharedTimer : public SharedTimer { |  | 
| 136 public: |  | 
| 137     explicit WorkerSharedTimer(WorkerThread* workerThread) |  | 
| 138         : m_workerThread(workerThread) |  | 
| 139         , m_running(false) |  | 
| 140     { } |  | 
| 141 |  | 
| 142     typedef void (*SharedTimerFunction)(); |  | 
| 143     virtual void setFiredFunction(SharedTimerFunction func) |  | 
| 144     { |  | 
| 145         m_sharedTimerFunction = func; |  | 
| 146     } |  | 
| 147 |  | 
| 148     virtual void setFireInterval(double interval) |  | 
| 149     { |  | 
| 150         ASSERT(m_sharedTimerFunction); |  | 
| 151 |  | 
| 152         // See BlinkPlatformImpl::setSharedTimerFireInterval for explanation of |  | 
| 153         // why ceil is used in the interval calculation. |  | 
| 154         int64_t delay = static_cast<int64_t>(ceil(interval * 1000)); |  | 
| 155 |  | 
| 156         if (delay < 0) { |  | 
| 157             delay = 0; |  | 
| 158         } |  | 
| 159 |  | 
| 160         m_running = true; |  | 
| 161 |  | 
| 162         if (m_lastQueuedTask.get()) |  | 
| 163             m_lastQueuedTask->cancelTask(); |  | 
| 164 |  | 
| 165         // Now queue the task as a cancellable one. |  | 
| 166         OwnPtr<WorkerThreadCancelableTask> task = WorkerThreadCancelableTask::cr
     eate(bind(&WorkerSharedTimer::OnTimeout, this)); |  | 
| 167         m_lastQueuedTask = task->createWeakPtr(); |  | 
| 168         m_workerThread->postDelayedTask(FROM_HERE, task.release(), delay); |  | 
| 169     } |  | 
| 170 |  | 
| 171     virtual void stop() |  | 
| 172     { |  | 
| 173         m_running = false; |  | 
| 174         m_lastQueuedTask = nullptr; |  | 
| 175     } |  | 
| 176 |  | 
| 177 private: |  | 
| 178     void OnTimeout() |  | 
| 179     { |  | 
| 180         ASSERT(m_workerThread->workerGlobalScope()); |  | 
| 181 |  | 
| 182         m_lastQueuedTask = nullptr; |  | 
| 183 |  | 
| 184         if (m_sharedTimerFunction && m_running && !m_workerThread->workerGlobalS
     cope()->isClosing()) |  | 
| 185             m_sharedTimerFunction(); |  | 
| 186     } |  | 
| 187 |  | 
| 188     WorkerThread* m_workerThread; |  | 
| 189     SharedTimerFunction m_sharedTimerFunction; |  | 
| 190     bool m_running; |  | 
| 191 |  | 
| 192     // The task to run OnTimeout, if any. While OnTimeout resets |  | 
| 193     // m_lastQueuedTask, this must be a weak pointer because the |  | 
| 194     // worker runloop may delete the task as it is shutting down. |  | 
| 195     WeakPtr<WorkerThreadCancelableTask> m_lastQueuedTask; |  | 
| 196 }; |  | 
| 197 |  | 
| 198 class WorkerThreadTask : public blink::WebThread::Task { | 102 class WorkerThreadTask : public blink::WebThread::Task { | 
| 199     WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED(WorkerThread
     Task); | 103     WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED(WorkerThread
     Task); | 
| 200 public: | 104 public: | 
| 201     static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO
     wnPtr<ExecutionContextTask> task, bool isInstrumented) | 105     static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO
     wnPtr<ExecutionContextTask> task, bool isInstrumented) | 
| 202     { | 106     { | 
| 203         return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented)
     ); | 107         return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented)
     ); | 
| 204     } | 108     } | 
| 205 | 109 | 
| 206     virtual ~WorkerThreadTask() { } | 110     virtual ~WorkerThreadTask() { } | 
| 207 | 111 | 
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 258 | 162 | 
| 259 WorkerThread::WorkerThread(const char* threadName, PassRefPtr<WorkerLoaderProxy>
      workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, PassOwnPtr<Worke
     rThreadStartupData> startupData) | 163 WorkerThread::WorkerThread(const char* threadName, PassRefPtr<WorkerLoaderProxy>
      workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, PassOwnPtr<Worke
     rThreadStartupData> startupData) | 
| 260     : m_threadName(threadName) | 164     : m_threadName(threadName) | 
| 261     , m_terminated(false) | 165     , m_terminated(false) | 
| 262     , m_workerLoaderProxy(workerLoaderProxy) | 166     , m_workerLoaderProxy(workerLoaderProxy) | 
| 263     , m_workerReportingProxy(workerReportingProxy) | 167     , m_workerReportingProxy(workerReportingProxy) | 
| 264     , m_startupData(startupData) | 168     , m_startupData(startupData) | 
| 265     , m_isolate(nullptr) | 169     , m_isolate(nullptr) | 
| 266     , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent()
     )) | 170     , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent()
     )) | 
| 267     , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEven
     t())) | 171     , m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEven
     t())) | 
|  | 172     , m_webScheduler(nullptr) | 
|  | 173     , m_preShutdown(false) | 
| 268 { | 174 { | 
| 269     MutexLocker lock(threadSetMutex()); | 175     MutexLocker lock(threadSetMutex()); | 
| 270     workerThreads().add(this); | 176     workerThreads().add(this); | 
| 271 } | 177 } | 
| 272 | 178 | 
| 273 WorkerThread::~WorkerThread() | 179 WorkerThread::~WorkerThread() | 
| 274 { | 180 { | 
| 275     MutexLocker lock(threadSetMutex()); | 181     MutexLocker lock(threadSetMutex()); | 
| 276     ASSERT(workerThreads().contains(this)); | 182     ASSERT(workerThreads().contains(this)); | 
| 277     workerThreads().remove(this); | 183     workerThreads().remove(this); | 
| 278 } | 184 } | 
| 279 | 185 | 
| 280 void WorkerThread::start() | 186 void WorkerThread::start() | 
| 281 { | 187 { | 
| 282     if (m_thread) | 188     if (m_thread) | 
| 283         return; | 189         return; | 
| 284 | 190 | 
| 285     m_thread = createWebThreadSupportingGC(); | 191     m_thread = createWebThreadSupportingGC(); | 
|  | 192     m_webScheduler = m_thread->platformThread().scheduler(); | 
| 286     m_thread->postTask(FROM_HERE, new Task(threadSafeBind(&WorkerThread::initial
     ize, AllowCrossThreadAccess(this)))); | 193     m_thread->postTask(FROM_HERE, new Task(threadSafeBind(&WorkerThread::initial
     ize, AllowCrossThreadAccess(this)))); | 
| 287 } | 194 } | 
| 288 | 195 | 
| 289 void WorkerThread::interruptAndDispatchInspectorCommands() | 196 void WorkerThread::interruptAndDispatchInspectorCommands() | 
| 290 { | 197 { | 
| 291     MutexLocker locker(m_workerInspectorControllerMutex); | 198     MutexLocker locker(m_workerInspectorControllerMutex); | 
| 292     if (m_workerInspectorController) | 199     if (m_workerInspectorController) | 
| 293         m_workerInspectorController->interruptAndDispatchInspectorCommands(); | 200         m_workerInspectorController->interruptAndDispatchInspectorCommands(); | 
| 294 } | 201 } | 
| 295 | 202 | 
| 296 PlatformThreadId WorkerThread::platformThreadId() const | 203 PlatformThreadId WorkerThread::platformThreadId() const | 
| 297 { | 204 { | 
| 298     if (!m_thread) | 205     if (!m_thread) | 
| 299         return 0; | 206         return 0; | 
| 300     return m_thread->platformThread().threadId(); | 207     return m_thread->platformThread().threadId(); | 
| 301 } | 208 } | 
| 302 | 209 | 
|  | 210 // TODO(alexclarke): Use base::Bind instead of this class when the repo's merge.
      Unfortunately we | 
|  | 211 // can't use WTF::bind because the type-erasure for member function pointers wit
     h parameters is broken. | 
|  | 212 class WorkerThreadIdleTask : public WebThread::IdleTask { | 
|  | 213 public: | 
|  | 214     explicit WorkerThreadIdleTask(WorkerThread* thread) | 
|  | 215         : m_thread(thread) { } | 
|  | 216 | 
|  | 217     ~WorkerThreadIdleTask() override { } | 
|  | 218 | 
|  | 219     void run(double deadlineSeconds) override | 
|  | 220     { | 
|  | 221         m_thread->idleTask(deadlineSeconds); | 
|  | 222     } | 
|  | 223 | 
|  | 224 private: | 
|  | 225     RawPtr<WorkerThread> m_thread; // NOT OWNED | 
|  | 226 }; | 
|  | 227 | 
| 303 void WorkerThread::initialize() | 228 void WorkerThread::initialize() | 
| 304 { | 229 { | 
| 305     KURL scriptURL = m_startupData->m_scriptURL; | 230     KURL scriptURL = m_startupData->m_scriptURL; | 
| 306     String sourceCode = m_startupData->m_sourceCode; | 231     String sourceCode = m_startupData->m_sourceCode; | 
| 307     WorkerThreadStartMode startMode = m_startupData->m_startMode; | 232     WorkerThreadStartMode startMode = m_startupData->m_startMode; | 
| 308     OwnPtr<Vector<char>> cachedMetaData = m_startupData->m_cachedMetaData.releas
     e(); | 233     OwnPtr<Vector<char>> cachedMetaData = m_startupData->m_cachedMetaData.releas
     e(); | 
| 309     V8CacheOptions v8CacheOptions = m_startupData->m_v8CacheOptions; | 234     V8CacheOptions v8CacheOptions = m_startupData->m_v8CacheOptions; | 
| 310 | 235 | 
| 311     { | 236     { | 
| 312         MutexLocker lock(m_threadCreationMutex); | 237         MutexLocker lock(m_threadCreationMutex); | 
| 313 | 238 | 
| 314         // The worker was terminated before the thread had a chance to run. | 239         // The worker was terminated before the thread had a chance to run. | 
| 315         if (m_terminated) { | 240         if (m_terminated) { | 
| 316             // Notify the proxy that the WorkerGlobalScope has been disposed of. | 241             // 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. | 242             // This can free this thread object, hence it must not be touched af
     terwards. | 
| 318             m_workerReportingProxy.workerThreadTerminated(); | 243             m_workerReportingProxy.workerThreadTerminated(); | 
| 319             return; | 244             return; | 
| 320         } | 245         } | 
| 321 | 246 | 
| 322         m_microtaskRunner = adoptPtr(new MicrotaskRunner(this)); | 247         m_microtaskRunner = adoptPtr(new MicrotaskRunner(this)); | 
| 323         m_thread->addTaskObserver(m_microtaskRunner.get()); | 248         m_thread->addTaskObserver(m_microtaskRunner.get()); | 
| 324         m_thread->attachGC(); | 249         m_thread->attachGC(); | 
| 325 | 250 | 
| 326         m_isolate = initializeIsolate(); | 251         m_isolate = initializeIsolate(); | 
| 327         m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release()); | 252         m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release()); | 
| 328         m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.ge
     t() ? cachedMetaData->size() : 0); | 253         m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.ge
     t() ? cachedMetaData->size() : 0); | 
| 329 |  | 
| 330         PlatformThreadData::current().threadTimers().setSharedTimer(adoptPtr(new
      WorkerSharedTimer(this))); |  | 
| 331     } | 254     } | 
| 332 | 255 | 
| 333     // The corresponding call to stopRunLoop() is in ~WorkerScriptController(). | 256     // The corresponding call to stopRunLoop() is in ~WorkerScriptController(). | 
| 334     didStartRunLoop(); | 257     didStartRunLoop(); | 
| 335 | 258 | 
| 336     // Notify proxy that a new WorkerGlobalScope has been created and started. | 259     // Notify proxy that a new WorkerGlobalScope has been created and started. | 
| 337     m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get()); | 260     m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get()); | 
| 338 | 261 | 
| 339     WorkerScriptController* script = m_workerGlobalScope->script(); | 262     WorkerScriptController* script = m_workerGlobalScope->script(); | 
| 340     if (!script->isExecutionForbidden()) | 263     if (!script->isExecutionForbidden()) | 
| 341         script->initializeContextIfNeeded(); | 264         script->initializeContextIfNeeded(); | 
| 342     if (startMode == PauseWorkerGlobalScopeOnStart) | 265     if (startMode == PauseWorkerGlobalScopeOnStart) | 
| 343         m_workerGlobalScope->workerInspectorController()->pauseOnStart(); | 266         m_workerGlobalScope->workerInspectorController()->pauseOnStart(); | 
| 344 | 267 | 
| 345     OwnPtr<CachedMetadataHandler> handler(workerGlobalScope()->createWorkerScrip
     tCachedMetadataHandler(scriptURL, cachedMetaData.get())); | 268     OwnPtr<CachedMetadataHandler> handler(workerGlobalScope()->createWorkerScrip
     tCachedMetadataHandler(scriptURL, cachedMetaData.get())); | 
| 346     bool success = script->evaluate(ScriptSourceCode(sourceCode, scriptURL), nul
     lptr, handler.get(), v8CacheOptions); | 269     bool success = script->evaluate(ScriptSourceCode(sourceCode, scriptURL), nul
     lptr, handler.get(), v8CacheOptions); | 
| 347     m_workerGlobalScope->didEvaluateWorkerScript(); | 270     m_workerGlobalScope->didEvaluateWorkerScript(); | 
| 348     m_workerReportingProxy.didEvaluateWorkerScript(success); | 271     m_workerReportingProxy.didEvaluateWorkerScript(success); | 
| 349 | 272 | 
| 350     postInitialize(); | 273     postInitialize(); | 
| 351 | 274 | 
| 352     postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, 
     this), kShortIdleHandlerDelayMs); | 275     m_webScheduler->postIdleTaskAfterWakeup(FROM_HERE, new WorkerThreadIdleTask(
     this)); | 
| 353 } | 276 } | 
| 354 | 277 | 
| 355 PassOwnPtr<WebThreadSupportingGC> WorkerThread::createWebThreadSupportingGC() | 278 PassOwnPtr<WebThreadSupportingGC> WorkerThread::createWebThreadSupportingGC() | 
| 356 { | 279 { | 
| 357     return WebThreadSupportingGC::create(m_threadName); | 280     return WebThreadSupportingGC::create(m_threadName); | 
| 358 } | 281 } | 
| 359 | 282 | 
| 360 void WorkerThread::cleanup() | 283 void WorkerThread::cleanup() | 
| 361 { | 284 { | 
| 362     // This should be called before we start the shutdown procedure. | 285     // This should be called before we start the shutdown procedure. | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 375     destroyIsolate(); | 298     destroyIsolate(); | 
| 376 | 299 | 
| 377     m_thread->removeTaskObserver(m_microtaskRunner.get()); | 300     m_thread->removeTaskObserver(m_microtaskRunner.get()); | 
| 378     m_microtaskRunner = nullptr; | 301     m_microtaskRunner = nullptr; | 
| 379 | 302 | 
| 380     // Notify the proxy that the WorkerGlobalScope has been disposed of. | 303     // Notify the proxy that the WorkerGlobalScope has been disposed of. | 
| 381     // This can free this thread object, hence it must not be touched afterwards
     . | 304     // This can free this thread object, hence it must not be touched afterwards
     . | 
| 382     workerReportingProxy().workerThreadTerminated(); | 305     workerReportingProxy().workerThreadTerminated(); | 
| 383 | 306 | 
| 384     m_terminationEvent->signal(); | 307     m_terminationEvent->signal(); | 
| 385 |  | 
| 386     // Clean up PlatformThreadData before WTF::WTFThreadData goes away! |  | 
| 387     PlatformThreadData::current().destroy(); |  | 
| 388 } | 308 } | 
| 389 | 309 | 
| 390 class WorkerThreadShutdownFinishTask : public ExecutionContextTask { | 310 class WorkerThreadShutdownFinishTask : public ExecutionContextTask { | 
| 391 public: | 311 public: | 
| 392     static PassOwnPtr<WorkerThreadShutdownFinishTask> create() | 312     static PassOwnPtr<WorkerThreadShutdownFinishTask> create() | 
| 393     { | 313     { | 
| 394         return adoptPtr(new WorkerThreadShutdownFinishTask()); | 314         return adoptPtr(new WorkerThreadShutdownFinishTask()); | 
| 395     } | 315     } | 
| 396 | 316 | 
| 397     virtual void performTask(ExecutionContext *context) | 317     virtual void performTask(ExecutionContext *context) | 
| 398     { | 318     { | 
| 399         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); | 319         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); | 
| 400         workerGlobalScope->dispose(); | 320         workerGlobalScope->dispose(); | 
| 401 | 321 | 
| 402         WorkerThread* workerThread = workerGlobalScope->thread(); | 322         WorkerThread* workerThread = workerGlobalScope->thread(); | 
| 403         workerThread->willDestroyIsolate(); | 323         workerThread->willDestroyIsolate(); | 
| 404         workerThread->m_thread->postTask(FROM_HERE, new Task(WTF::bind(&WorkerTh
     read::cleanup, workerThread))); | 324         workerThread->m_webScheduler->postShutdownTask(FROM_HERE, new Task(WTF::
     bind(&WorkerThread::cleanup, workerThread)), 0); | 
| 405     } | 325     } | 
| 406 | 326 | 
| 407     virtual bool isCleanupTask() const { return true; } | 327     virtual bool isCleanupTask() const { return true; } | 
| 408 }; | 328 }; | 
| 409 | 329 | 
| 410 class WorkerThreadShutdownStartTask : public ExecutionContextTask { | 330 class WorkerThreadShutdownStartTask : public ExecutionContextTask { | 
| 411 public: | 331 public: | 
| 412     static PassOwnPtr<WorkerThreadShutdownStartTask> create() | 332     static PassOwnPtr<WorkerThreadShutdownStartTask> create() | 
| 413     { | 333     { | 
| 414         return adoptPtr(new WorkerThreadShutdownStartTask()); | 334         return adoptPtr(new WorkerThreadShutdownStartTask()); | 
| 415     } | 335     } | 
| 416 | 336 | 
| 417     virtual void performTask(ExecutionContext *context) | 337     virtual void performTask(ExecutionContext *context) | 
| 418     { | 338     { | 
| 419         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); | 339         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); | 
| 420         workerGlobalScope->stopActiveDOMObjects(); | 340         workerGlobalScope->stopActiveDOMObjects(); | 
| 421         PlatformThreadData::current().threadTimers().setSharedTimer(nullptr); |  | 
| 422 | 341 | 
| 423         // Event listeners would keep DOMWrapperWorld objects alive for too long
     . Also, they have references to JS objects, | 342         // Event listeners would keep DOMWrapperWorld objects alive for too long
     . Also, they have references to JS objects, | 
| 424         // which become dangling once Heap is destroyed. | 343         // which become dangling once Heap is destroyed. | 
| 425         workerGlobalScope->removeAllEventListeners(); | 344         workerGlobalScope->removeAllEventListeners(); | 
| 426 | 345 | 
| 427         // Stick a shutdown command at the end of the queue, so that we deal | 346         // Stick a shutdown command at the end of the queue, so that we deal | 
| 428         // with all the cleanup tasks the databases post first. | 347         // with all the cleanup tasks the databases post first. | 
| 429         workerGlobalScope->postTask(FROM_HERE, WorkerThreadShutdownFinishTask::c
     reate()); | 348         workerGlobalScope->postTask(FROM_HERE, WorkerThreadShutdownFinishTask::c
     reate()); | 
| 430     } | 349     } | 
| 431 | 350 | 
| 432     virtual bool isCleanupTask() const { return true; } | 351     virtual bool isCleanupTask() const { return true; } | 
| 433 }; | 352 }; | 
| 434 | 353 | 
|  | 354 class PreShutDownTask : public WebThread::Task { | 
|  | 355 public: | 
|  | 356     PreShutDownTask(WebWaitableEvent* completion, WebScheduler* webScheduler) | 
|  | 357         : m_completion(completion) | 
|  | 358         , m_webScheduler(webScheduler) { } | 
|  | 359 | 
|  | 360     ~PreShutDownTask() override { } | 
|  | 361 | 
|  | 362     void run() | 
|  | 363     { | 
|  | 364         m_webScheduler->preShutdown(); | 
|  | 365         m_completion->signal(); | 
|  | 366     } | 
|  | 367 | 
|  | 368 private: | 
|  | 369     RawPtr<WebWaitableEvent> m_completion; // NOT OWNED. | 
|  | 370     RawPtr<WebScheduler> m_webScheduler; // NOT OWNED. | 
|  | 371 }; | 
|  | 372 | 
|  | 373 void WorkerThread::preShutdown() | 
|  | 374 { | 
|  | 375     MutexLocker lock(m_preShutdownMutex); | 
|  | 376     if (m_preShutdown || !m_webScheduler) | 
|  | 377         return; | 
|  | 378     m_preShutdown = true; | 
|  | 379 | 
|  | 380     if (m_thread->isCurrentThread()) { | 
|  | 381         m_webScheduler->preShutdown(); | 
|  | 382     } else { | 
|  | 383         OwnPtr<WebWaitableEvent> completion(adoptPtr(blink::Platform::current()-
     >createWaitableEvent())); | 
|  | 384         m_thread->postTask(FROM_HERE, new PreShutDownTask(completion.get(), m_we
     bScheduler.get())); | 
|  | 385         completion->wait(); | 
|  | 386     } | 
|  | 387 } | 
|  | 388 | 
| 435 void WorkerThread::stop() | 389 void WorkerThread::stop() | 
| 436 { | 390 { | 
| 437     // Prevent the deadlock between GC and an attempt to stop a thread. | 391     // Prevent the deadlock between GC and an attempt to stop a thread. | 
| 438     SafePointScope safePointScope(ThreadState::HeapPointersOnStack); | 392     SafePointScope safePointScope(ThreadState::HeapPointersOnStack); | 
| 439     stopInternal(); | 393     stopInternal(); | 
| 440 } | 394 } | 
| 441 | 395 | 
| 442 void WorkerThread::stopInShutdownSequence() | 396 void WorkerThread::stopInShutdownSequence() | 
| 443 { | 397 { | 
| 444     stopInternal(); | 398     stopInternal(); | 
| 445 } | 399 } | 
| 446 | 400 | 
| 447 void WorkerThread::terminateAndWait() | 401 void WorkerThread::terminateAndWait() | 
| 448 { | 402 { | 
| 449     stop(); | 403     stop(); | 
| 450     m_terminationEvent->wait(); | 404     m_terminationEvent->wait(); | 
| 451 } | 405 } | 
| 452 | 406 | 
| 453 bool WorkerThread::terminated() | 407 bool WorkerThread::terminated() | 
| 454 { | 408 { | 
| 455     MutexLocker lock(m_threadCreationMutex); | 409     MutexLocker lock(m_threadCreationMutex); | 
| 456     return m_terminated; | 410     return m_terminated; | 
| 457 } | 411 } | 
| 458 | 412 | 
| 459 void WorkerThread::stopInternal() | 413 void WorkerThread::stopInternal() | 
| 460 { | 414 { | 
| 461     // Protect against this method and initialize() racing each other. | 415     // Protect against this method and initialize() racing each other. | 
| 462     MutexLocker lock(m_threadCreationMutex); | 416     { | 
|  | 417         MutexLocker lock(m_threadCreationMutex); | 
| 463 | 418 | 
| 464     // If stop has already been called, just return. | 419         // If stop has already been called, just return. | 
| 465     if (m_terminated) | 420         if (m_terminated) | 
| 466         return; | 421             return; | 
| 467     m_terminated = true; | 422         m_terminated = true; | 
| 468 | 423 | 
| 469     // Signal the thread to notify that the thread's stopping. | 424         // Signal the thread to notify that the thread's stopping. | 
| 470     if (m_shutdownEvent) | 425         if (m_shutdownEvent) | 
| 471         m_shutdownEvent->signal(); | 426             m_shutdownEvent->signal(); | 
| 472 | 427 | 
| 473     if (!m_workerGlobalScope) | 428         if (!m_workerGlobalScope) | 
| 474         return; | 429             return; | 
| 475 | 430 | 
| 476     // 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. | 431         // Ensure that tasks are being handled by thread event loop. If script e
     xecution weren't forbidden, a while(1) loop in JS could keep the thread alive fo
     rever. | 
| 477     terminateV8Execution(); | 432         terminateV8Execution(); | 
| 478 | 433 | 
| 479     InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScop
     e.get()); | 434         InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobal
     Scope.get()); | 
| 480     m_debuggerMessageQueue.kill(); | 435         m_debuggerMessageQueue.kill(); | 
| 481     postTask(FROM_HERE, WorkerThreadShutdownStartTask::create()); | 436         postTask(FROM_HERE, WorkerThreadShutdownStartTask::create()); | 
|  | 437     } | 
|  | 438     // Prevent further execution of non-shutdown tasks on the thread.  Must happ
     en after any v8 task has been terminated. | 
|  | 439     preShutdown(); | 
| 482 } | 440 } | 
| 483 | 441 | 
| 484 void WorkerThread::didStartRunLoop() | 442 void WorkerThread::didStartRunLoop() | 
| 485 { | 443 { | 
| 486     ASSERT(isCurrentThread()); | 444     ASSERT(isCurrentThread()); | 
| 487     blink::Platform::current()->didStartWorkerRunLoop(); | 445     blink::Platform::current()->didStartWorkerRunLoop(); | 
| 488 } | 446 } | 
| 489 | 447 | 
| 490 void WorkerThread::didStopRunLoop() | 448 void WorkerThread::didStopRunLoop() | 
| 491 { | 449 { | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 503 | 461 | 
| 504     for (WorkerThread* thread : threads) | 462     for (WorkerThread* thread : threads) | 
| 505         thread->terminationEvent()->wait(); | 463         thread->terminationEvent()->wait(); | 
| 506 } | 464 } | 
| 507 | 465 | 
| 508 bool WorkerThread::isCurrentThread() const | 466 bool WorkerThread::isCurrentThread() const | 
| 509 { | 467 { | 
| 510     return m_thread && m_thread->isCurrentThread(); | 468     return m_thread && m_thread->isCurrentThread(); | 
| 511 } | 469 } | 
| 512 | 470 | 
| 513 void WorkerThread::idleHandler() | 471 void WorkerThread::idleTask(double deadlineSeconds) | 
| 514 { | 472 { | 
| 515     ASSERT(m_workerGlobalScope.get()); | 473     if (terminated()) | 
| 516     int64_t delay = kLongIdleHandlerDelayMs; | 474         return; | 
| 517 | 475 | 
| 518     // Do a script engine idle notification if the next event is distant enough. | 476     double gcDeadlineSeconds = deadlineSeconds; | 
| 519     const double kMinIdleTimespan = 0.3; |  | 
| 520     const double nextFireTime = PlatformThreadData::current().threadTimers().nex
     tFireTime(); |  | 
| 521     if (nextFireTime == 0.0 || nextFireTime > currentTime() + kMinIdleTimespan) 
     { |  | 
| 522         bool hasMoreWork = !isolate()->IdleNotificationDeadline(Platform::curren
     t()->monotonicallyIncreasingTime() + 1.0); |  | 
| 523         if (hasMoreWork) |  | 
| 524             delay = kShortIdleHandlerDelayMs; |  | 
| 525     } |  | 
| 526 | 477 | 
| 527     postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, 
     this), delay); | 478     // The V8 GC does some GC steps (e.g. compaction) only when the idle notific
     ation is ~1s. | 
|  | 479     // TODO(rmcilroy): Refactor so extending the deadline like this this isn't n
     eeded. | 
|  | 480     if (m_webScheduler->canExceedIdleDeadlineIfRequired()) | 
|  | 481         gcDeadlineSeconds = Platform::current()->monotonicallyIncreasingTime() +
      kLongIdleHandlerDelaySecs; | 
|  | 482 | 
|  | 483     if (doIdleGc(gcDeadlineSeconds)) | 
|  | 484         m_webScheduler->postIdleTaskAfterWakeup(FROM_HERE, new WorkerThreadIdleT
     ask(this)); | 
|  | 485     else | 
|  | 486         m_webScheduler->postIdleTask(FROM_HERE, new WorkerThreadIdleTask(this)); | 
|  | 487 } | 
|  | 488 | 
|  | 489 bool WorkerThread::doIdleGc(double deadlineSeconds) | 
|  | 490 { | 
|  | 491     bool gcFinished = false; | 
|  | 492     if (deadlineSeconds > Platform::current()->monotonicallyIncreasingTime()) | 
|  | 493         gcFinished = isolate()->IdleNotificationDeadline(deadlineSeconds); | 
|  | 494     return gcFinished; | 
| 528 } | 495 } | 
| 529 | 496 | 
| 530 void WorkerThread::postTask(const WebTraceLocation& location, PassOwnPtr<Executi
     onContextTask> task) | 497 void WorkerThread::postTask(const WebTraceLocation& location, PassOwnPtr<Executi
     onContextTask> task) | 
| 531 { | 498 { | 
| 532     m_thread->postTask(location, WorkerThreadTask::create(*this, task, true).lea
     kPtr()); | 499     if (task->isCleanupTask()) | 
|  | 500         m_webScheduler->postShutdownTask(location, WorkerThreadTask::create(*thi
     s, task, true).leakPtr(), 0); | 
|  | 501     else | 
|  | 502         m_thread->postTask(location, WorkerThreadTask::create(*this, task, true)
     .leakPtr()); | 
| 533 } | 503 } | 
| 534 | 504 | 
| 535 void WorkerThread::postDelayedTask(const WebTraceLocation& location, PassOwnPtr<
     ExecutionContextTask> task, long long delayMs) | 505 void WorkerThread::postDelayedTask(const WebTraceLocation& location, PassOwnPtr<
     ExecutionContextTask> task, long long delayMs) | 
| 536 { | 506 { | 
| 537     m_thread->postDelayedTask(location, WorkerThreadTask::create(*this, task, tr
     ue).leakPtr(), delayMs); | 507     if (task->isCleanupTask()) | 
|  | 508         m_webScheduler->postShutdownTask(location, WorkerThreadTask::create(*thi
     s, task, true).leakPtr(), delayMs); | 
|  | 509     else | 
|  | 510         m_thread->postDelayedTask(location, WorkerThreadTask::create(*this, task
     , true).leakPtr(), delayMs); | 
| 538 } | 511 } | 
| 539 | 512 | 
| 540 v8::Isolate* WorkerThread::initializeIsolate() | 513 v8::Isolate* WorkerThread::initializeIsolate() | 
| 541 { | 514 { | 
| 542     ASSERT(isCurrentThread()); | 515     ASSERT(isCurrentThread()); | 
| 543     ASSERT(!m_isolate); | 516     ASSERT(!m_isolate); | 
| 544     v8::Isolate* isolate = V8PerIsolateData::initialize(); | 517     v8::Isolate* isolate = V8PerIsolateData::initialize(); | 
| 545     V8Initializer::initializeWorker(isolate); | 518     V8Initializer::initializeWorker(isolate); | 
| 546 | 519 | 
| 547     m_interruptor = adoptPtr(new V8IsolateInterruptor(isolate)); | 520     m_interruptor = adoptPtr(new V8IsolateInterruptor(isolate)); | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 611     InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get()); | 584     InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get()); | 
| 612 } | 585 } | 
| 613 | 586 | 
| 614 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke
     rInspectorController) | 587 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke
     rInspectorController) | 
| 615 { | 588 { | 
| 616     MutexLocker locker(m_workerInspectorControllerMutex); | 589     MutexLocker locker(m_workerInspectorControllerMutex); | 
| 617     m_workerInspectorController = workerInspectorController; | 590     m_workerInspectorController = workerInspectorController; | 
| 618 } | 591 } | 
| 619 | 592 | 
| 620 } // namespace blink | 593 } // namespace blink | 
| OLD | NEW | 
|---|