Changeset 240042 in webkit
- Timestamp:
- Jan 16, 2019 11:07:22 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r240039 r240042 1 2019-01-16 Youenn Fablet <youenn@apple.com> 2 3 Prevent WorkerRunLoop::runInMode from spinning in nested cases 4 https://bugs.webkit.org/show_bug.cgi?id=193359 5 <rdar://problem/46345353> 6 7 Reviewed by Joseph Pecoraro. 8 9 Speculative fix for some cases where service worker is spinning and consuming a lot of CPU. 10 The hypothesis is that: 11 - Service Worker is checking for its script freshness through WorkerScriptLoader. 12 This triggers the worker run loop to be nested. 13 - The run loop timer is active and needs to fire immediately. 14 The hypothesis is that this happens in some cases like restarting a device after sleep mode. 15 16 WorkerRunLoop::runInMode will then compute a 0 timeout value for getting a message. 17 This will trigger a timeout while waiting for the message queue. 18 Since the run loop is nested, the run loop timer will not be able to fire, 19 and it will keep ask to fire immediately. 20 runInMode will return timeout as a result and WorkerRunLoop::run will call it immediately. 21 22 The fix is to prevent the shared timer to fire only when the run loop is being debugged through the web inspector. 23 We compute this by checking the run loop mode as debuggerMode(). 24 Did some refactoring by introducing helper routines for running the loop and posting task in debugger mode. 25 26 * inspector/WorkerScriptDebugServer.cpp: 27 (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused): 28 * workers/WorkerInspectorProxy.cpp: 29 (WebCore::WorkerInspectorProxy::resumeWorkerIfPaused): 30 (WebCore::WorkerInspectorProxy::connectToWorkerInspectorController): 31 (WebCore::WorkerInspectorProxy::disconnectFromWorkerInspectorController): 32 (WebCore::WorkerInspectorProxy::sendMessageToWorkerInspectorController): 33 * workers/WorkerRunLoop.cpp: 34 (WebCore::ModePredicate::ModePredicate): 35 (WebCore::WorkerRunLoop::WorkerRunLoop): 36 (WebCore::debuggerMode): 37 (WebCore::RunLoopSetup::RunLoopSetup): 38 (WebCore::RunLoopSetup::~RunLoopSetup): 39 (WebCore::WorkerRunLoop::run): 40 (WebCore::WorkerRunLoop::runInDebuggerMode): 41 (WebCore::WorkerRunLoop::runInMode): 42 (WebCore::WorkerRunLoop::Task::performTask): 43 * workers/WorkerRunLoop.h: 44 (WebCore::WorkerRunLoop::isBeingDebugged const): 45 * workers/WorkerThread.cpp: 46 (WebCore::WorkerThread::startRunningDebuggerTasks): 47 * workers/service/context/ServiceWorkerInspectorProxy.cpp: 48 (WebCore::ServiceWorkerInspectorProxy::connectToWorker): 49 (WebCore::ServiceWorkerInspectorProxy::disconnectFromWorker): 50 (WebCore::ServiceWorkerInspectorProxy::sendMessageToWorker): 51 1 52 2019-01-16 Sihui Liu <sihui_liu@apple.com> 2 53 -
trunk/Source/WebCore/inspector/WorkerScriptDebugServer.cpp
r228218 r240042 75 75 MessageQueueWaitResult result; 76 76 do { 77 result = m_workerGlobalScope.thread().runLoop().runIn Mode(&m_workerGlobalScope, WorkerRunLoop::debuggerMode());77 result = m_workerGlobalScope.thread().runLoop().runInDebuggerMode(m_workerGlobalScope); 78 78 } while (result != MessageQueueTerminated && !m_doneProcessingDebuggerEvents); 79 79 } -
trunk/Source/WebCore/workers/WorkerInspectorProxy.cpp
r228218 r240042 91 91 void WorkerInspectorProxy::resumeWorkerIfPaused() 92 92 { 93 m_workerThread->runLoop().post TaskForMode([] (ScriptExecutionContext& context) {93 m_workerThread->runLoop().postDebuggerTask([] (ScriptExecutionContext& context) { 94 94 downcast<WorkerGlobalScope>(context).thread().stopRunningDebuggerTasks(); 95 } , WorkerRunLoop::debuggerMode());95 }); 96 96 } 97 97 … … 104 104 m_pageChannel = channel; 105 105 106 m_workerThread->runLoop().post TaskForMode([] (ScriptExecutionContext& context) {106 m_workerThread->runLoop().postDebuggerTask([] (ScriptExecutionContext& context) { 107 107 downcast<WorkerGlobalScope>(context).inspectorController().connectFrontend(); 108 } , WorkerRunLoop::debuggerMode());108 }); 109 109 } 110 110 … … 117 117 m_pageChannel = nullptr; 118 118 119 m_workerThread->runLoop().post TaskForMode([] (ScriptExecutionContext& context) {119 m_workerThread->runLoop().postDebuggerTask([] (ScriptExecutionContext& context) { 120 120 downcast<WorkerGlobalScope>(context).inspectorController().disconnectFrontend(DisconnectReason::InspectorDestroyed); 121 121 … … 123 123 // the pause since this will be the last debugger task we send to the worker. 124 124 downcast<WorkerGlobalScope>(context).thread().stopRunningDebuggerTasks(); 125 } , WorkerRunLoop::debuggerMode());125 }); 126 126 } 127 127 … … 132 132 return; 133 133 134 m_workerThread->runLoop().post TaskForMode([message = message.isolatedCopy()] (ScriptExecutionContext& context) {134 m_workerThread->runLoop().postDebuggerTask([message = message.isolatedCopy()] (ScriptExecutionContext& context) { 135 135 downcast<WorkerGlobalScope>(context).inspectorController().dispatchMessageFromFrontend(message); 136 } , WorkerRunLoop::debuggerMode());136 }); 137 137 } 138 138 -
trunk/Source/WebCore/workers/WorkerRunLoop.cpp
r233122 r240042 65 65 class ModePredicate { 66 66 public: 67 ModePredicate(const String& mode)68 : m_mode( mode)69 , m_defaultMode(m ode == WorkerRunLoop::defaultMode())67 explicit ModePredicate(String&& mode) 68 : m_mode(WTFMove(mode)) 69 , m_defaultMode(m_mode == WorkerRunLoop::defaultMode()) 70 70 { 71 71 } … … 88 88 WorkerRunLoop::WorkerRunLoop() 89 89 : m_sharedTimer(std::make_unique<WorkerSharedTimer>()) 90 , m_nestedCount(0)91 , m_uniqueId(0)92 90 { 93 91 } … … 103 101 } 104 102 105 String WorkerRunLoop::debuggerMode()103 static String debuggerMode() 106 104 { 107 105 return "debugger"_s; … … 111 109 WTF_MAKE_NONCOPYABLE(RunLoopSetup); 112 110 public: 113 RunLoopSetup(WorkerRunLoop& runLoop) 111 enum class IsForDebugging { No, Yes }; 112 RunLoopSetup(WorkerRunLoop& runLoop, IsForDebugging isForDebugging) 114 113 : m_runLoop(runLoop) 114 , m_isForDebugging(isForDebugging) 115 115 { 116 116 if (!m_runLoop.m_nestedCount) 117 117 threadGlobalData().threadTimers().setSharedTimer(m_runLoop.m_sharedTimer.get()); 118 118 m_runLoop.m_nestedCount++; 119 if (m_isForDebugging == IsForDebugging::Yes) 120 m_runLoop.m_debugCount++; 119 121 } 120 122 … … 124 126 if (!m_runLoop.m_nestedCount) 125 127 threadGlobalData().threadTimers().setSharedTimer(nullptr); 128 if (m_isForDebugging == IsForDebugging::Yes) 129 m_runLoop.m_debugCount--; 126 130 } 127 131 private: 128 132 WorkerRunLoop& m_runLoop; 133 IsForDebugging m_isForDebugging { IsForDebugging::No }; 129 134 }; 130 135 131 136 void WorkerRunLoop::run(WorkerGlobalScope* context) 132 137 { 133 RunLoopSetup setup(*this );138 RunLoopSetup setup(*this, RunLoopSetup::IsForDebugging::No); 134 139 ModePredicate modePredicate(defaultMode()); 135 140 MessageQueueWaitResult result; … … 140 145 } 141 146 147 MessageQueueWaitResult WorkerRunLoop::runInDebuggerMode(WorkerGlobalScope& context) 148 { 149 RunLoopSetup setup(*this, RunLoopSetup::IsForDebugging::Yes); 150 return runInMode(&context, ModePredicate { debuggerMode() }, WaitForMessage); 151 } 152 142 153 MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerGlobalScope* context, const String& mode, WaitMode waitMode) 143 154 { 144 RunLoopSetup setup(*this); 145 ModePredicate modePredicate(mode); 155 ASSERT(mode != debuggerMode()); 156 RunLoopSetup setup(*this, RunLoopSetup::IsForDebugging::No); 157 ModePredicate modePredicate(String { mode }); 146 158 MessageQueueWaitResult result = runInMode(context, modePredicate, waitMode); 147 159 return result; … … 156 168 // We don't actually do anything here, we just want to loop around runInMode 157 169 // to both recalculate our deadline and to potentially run the run loop. 158 this->postTask([](ScriptExecutionContext&) { }); 170 this->postTask([](ScriptExecutionContext&) { }); 159 171 }); 160 172 … … 203 215 204 216 case MessageQueueTimeout: 205 if (!context->isClosing() && !is Nested())217 if (!context->isClosing() && !isBeingDebugged()) 206 218 m_sharedTimer->fire(); 207 219 break; … … 252 264 } 253 265 266 void WorkerRunLoop::postDebuggerTask(ScriptExecutionContext::Task&& task) 267 { 268 postTaskForMode(WTFMove(task), debuggerMode()); 269 } 270 254 271 void WorkerRunLoop::Task::performTask(WorkerGlobalScope* context) 255 272 { -
trunk/Source/WebCore/workers/WorkerRunLoop.h
r216876 r240042 54 54 // Waits for a single task and returns. 55 55 MessageQueueWaitResult runInMode(WorkerGlobalScope*, const String& mode, WaitMode = WaitForMessage); 56 MessageQueueWaitResult runInDebuggerMode(WorkerGlobalScope&); 56 57 57 58 void terminate(); … … 61 62 void postTaskAndTerminate(ScriptExecutionContext::Task&&); 62 63 void postTaskForMode(ScriptExecutionContext::Task&&, const String& mode); 64 void postDebuggerTask(ScriptExecutionContext::Task&&); 63 65 64 66 unsigned long createUniqueId() { return ++m_uniqueId; } 65 67 66 68 static String defaultMode(); 67 static String debuggerMode();68 69 69 class Task { 70 70 WTF_MAKE_NONCOPYABLE(Task); WTF_MAKE_FAST_ALLOCATED; … … 90 90 void runCleanupTasks(WorkerGlobalScope*); 91 91 92 bool is Nested() const { return m_nestedCount >1; }92 bool isBeingDebugged() const { return m_debugCount >= 1; } 93 93 94 94 MessageQueue<Task> m_messageQueue; 95 95 std::unique_ptr<WorkerSharedTimer> m_sharedTimer; 96 int m_nestedCount; 97 unsigned long m_uniqueId; 96 int m_nestedCount { 0 }; 97 int m_debugCount { 0 }; 98 unsigned long m_uniqueId { 0 }; 98 99 }; 99 100 -
trunk/Source/WebCore/workers/WorkerThread.cpp
r239569 r240042 250 250 MessageQueueWaitResult result; 251 251 do { 252 result = m_runLoop.runIn Mode(m_workerGlobalScope.get(), WorkerRunLoop::debuggerMode());252 result = m_runLoop.runInDebuggerMode(*m_workerGlobalScope); 253 253 } while (result != MessageQueueTerminated && m_pausedForDebugger); 254 254 } -
trunk/Source/WebCore/workers/service/context/ServiceWorkerInspectorProxy.cpp
r238206 r240042 62 62 m_channel = &channel; 63 63 64 m_serviceWorkerThreadProxy.thread().runLoop().post TaskForMode([] (ScriptExecutionContext& context) {64 m_serviceWorkerThreadProxy.thread().runLoop().postDebuggerTask([] (ScriptExecutionContext& context) { 65 65 downcast<WorkerGlobalScope>(context).inspectorController().connectFrontend(); 66 } , WorkerRunLoop::debuggerMode());66 }); 67 67 } 68 68 … … 72 72 m_channel = nullptr; 73 73 74 m_serviceWorkerThreadProxy.thread().runLoop().post TaskForMode([] (ScriptExecutionContext& context) {74 m_serviceWorkerThreadProxy.thread().runLoop().postDebuggerTask([] (ScriptExecutionContext& context) { 75 75 downcast<WorkerGlobalScope>(context).inspectorController().disconnectFrontend(DisconnectReason::InspectorDestroyed); 76 76 … … 78 78 // the pause since this will be the last debugger task we send to the worker. 79 79 downcast<WorkerGlobalScope>(context).thread().stopRunningDebuggerTasks(); 80 } , WorkerRunLoop::debuggerMode());80 }); 81 81 } 82 82 83 83 void ServiceWorkerInspectorProxy::sendMessageToWorker(const String& message) 84 84 { 85 m_serviceWorkerThreadProxy.thread().runLoop().post TaskForMode([message = message.isolatedCopy()] (ScriptExecutionContext& context) {85 m_serviceWorkerThreadProxy.thread().runLoop().postDebuggerTask([message = message.isolatedCopy()] (ScriptExecutionContext& context) { 86 86 downcast<WorkerGlobalScope>(context).inspectorController().dispatchMessageFromFrontend(message); 87 } , WorkerRunLoop::debuggerMode());87 }); 88 88 } 89 89
Note: See TracChangeset
for help on using the changeset viewer.