Changeset 57349 in webkit
- Timestamp:
- Apr 9, 2010 12:29:43 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r57346 r57349 1 2010-04-09 Dmitry Titov <dimich@chromium.org> 2 3 Reviewed by Darin Adler. 4 5 WebCore: WorkerGlobalScope.close() should let the currently running script complete execution, then terminate the worker. 6 https://bugs.webkit.org/show_bug.cgi?id=37053 7 8 * fast/workers/resources/worker-close.js: 9 * fast/workers/worker-close-expected.txt: 10 Updated tests to expect the script fragment that includes close() to run to completion. 11 12 * fast/workers/worker-close-more-expected.txt: Added. 13 * fast/workers/worker-close-more.html: Added. 14 * fast/workers/worker-close.html: 15 Added test to check terminate() after close() and close() in the case of multiple MessagePort messages dispatching. 16 1 17 2010-04-09 Kent Tamura <tkent@chromium.org> 2 18 -
trunk/LayoutTests/fast/workers/resources/worker-close.js
r46830 r57349 18 18 } else if (evt.data == "close") { 19 19 close(); 20 postMessage("Should notbe delivered");20 postMessage("Should be delivered"); 21 21 } else if (evt.data == "ping") { 22 22 postMessage("pong"); … … 26 26 close(); 27 27 nonExistentFunction(); // Undefined function - throws exception 28 } else if (evt.data == "close_post_loop") { 29 close(); 30 postMessage("closed"); 31 while(true) {} // Should loop forever. 32 } else if (evt.data == "take_port") { 33 messagePort = evt.ports[0]; 34 messagePort.onmessage = function(event) { 35 close(); 36 postMessage("echo_" + event.data); 37 } 38 } else if (evt.data == "start_port") { 39 messagePort.start(); 28 40 } else { 29 41 postMessage("FAIL: Unknown message type: " + evt.data); -
trunk/LayoutTests/fast/workers/worker-close-expected.txt
r46830 r57349 3 3 PASS: typeof close: function 4 4 PASS: received message before close 5 PASS: messages sent after close() are ignored 5 PASS: Received message posted right after close() was invoked: Should be delivered 6 PASS: no messages arrive to worker after JS fragment with close() exits 6 7 PASS: Error arrived after close: ReferenceError: Can't find variable: nonExistentFunction 7 8 PASS: close() did not dispatch pending events 9 PASS: Received message after worker closed: Should be delivered 8 10 DONE 9 11 -
trunk/LayoutTests/fast/workers/worker-close.html
r46830 r57349 36 36 log("FAIL: received unknown response: " + evt.data); 37 37 38 // Tell the worker to close, then send a followup message 39 // which should not be delivered. 38 // Tell the worker to close, then send a followup message. This message should not be delivered, 39 // since that would require JS to invoke the onmessage handler, which does not happen after the JS 40 // fragment with 'close()' in it exits. So, the 'ping' should not come back as 'pong'. 40 41 worker.postMessage("close"); 42 worker.postMessage("ping"); 41 43 worker.onmessage = function(evt) { 42 log("FAIL: Received message after worker closed: " + evt.data); 43 done(); 44 if (evt.data != "pong") 45 log("PASS: Received message posted right after close() was invoked: " + evt.data); 46 else { 47 log("FAIL: Received a message originated from a handler in the worker after the JS fragment with close() exited" + evt.data); 48 done(); 49 } 44 50 }; 45 // Make sure that messages don't arrive at the remote end - since they46 // can't send back response messages, we'll have the worker throw an47 // exception instead (errors are still propagated to the caller even after48 // close()).49 worker.postMessage("throw");50 worker.onerror = function(evt) {51 log("FAIL: message delivered after close(): " + evt.message);52 done();53 }54 51 timeout = setTimeout(testErrorAfterClose, 1000); 55 52 } … … 57 54 function testErrorAfterClose() 58 55 { 59 log("PASS: messages sent after close() are ignored");56 log("PASS: no messages arrive to worker after JS fragment with close() exits"); 60 57 // Test that errors are delivered after close. 61 58 worker = new Worker('resources/worker-close.js'); … … 87 84 { 88 85 log("PASS: close() did not dispatch pending events"); 89 worker = new Worker('resources/worker-cl ass.js');86 worker = new Worker('resources/worker-close.js'); 90 87 worker.postMessage("close"); 91 88 worker.onmessage = function(evt) { 92 log("FAIL: Received message after worker closed: " + evt.data); 93 done(); 89 log("PASS: Received message after worker closed: " + evt.data); 94 90 }; 95 91 // Give worker a chance to close first, then terminate it. -
trunk/WebCore/ChangeLog
r57346 r57349 1 2010-04-09 Dmitry Titov <dimich@chromium.org> 2 3 Reviewed by Darin Adler. 4 5 WebCore: WorkerGlobalScope.close() should let the currently running script complete execution, then terminate the worker. 6 https://bugs.webkit.org/show_bug.cgi?id=37053 7 8 Test: fast/workers/worker-close-more.html 9 10 * bindings/js/WorkerScriptController.cpp: 11 (WebCore::WorkerScriptController::forbidExecution): 12 (WebCore::WorkerScriptController::): 13 * bindings/v8/WorkerScriptController.cpp: 14 (WebCore::WorkerScriptController::forbidExecution): 15 * bindings/v8/WorkerScriptController.h: 16 (WebCore::WorkerScriptController::): 17 Added option parameter to forbidExecution (both JCS and V8 versions) that specifies whether currently running 18 script should be immediately terminated or left executed until the end. 19 20 * bindings/js/WorkerScriptController.h: 21 (WebCore::WorkerScriptController::workerContextWrapper): 22 This method now can return 0 instead of context if the further execution of JS is forbidden. Since any JS execution requires 23 fetching JS global object first, returning 0 here is a good way to prevent re-entry into JS once worker started termination. 24 V8 version does similar thing already in WorkerScriptController::proxy(). 25 26 * workers/DedicatedWorkerContext.cpp: 27 (WebCore::DedicatedWorkerContext::postMessage): 28 Removed check that immediately disables postMessage from WorkerContext after close(). 29 30 * workers/WorkerContext.cpp: 31 (WebCore::CloseWorkerContextTask::create): 32 (WebCore::CloseWorkerContextTask::performTask): 33 (WebCore::CloseWorkerContextTask::isCleanupTask): 34 (WebCore::WorkerContext::close): 35 Use new forbidExecution(LetRunningScriptFinish) to avoid termination of script until it executes and exits. 36 Post a task to actually terminate the worker once the currently executing JS fragment exits. 37 38 * workers/WorkerThread.cpp: 39 (WebCore::WorkerThread::workerThread): 40 (WebCore::WorkerThread::stop): 41 Use new forbidExecution(TerminateRunningScript) to immediately terminate the JS. 42 1 43 2010-04-09 Kent Tamura <tkent@chromium.org> 2 44 -
trunk/WebCore/bindings/js/WorkerScriptController.cpp
r57192 r57349 137 137 } 138 138 139 void WorkerScriptController::forbidExecution( )139 void WorkerScriptController::forbidExecution(ForbidExecutionOption option) 140 140 { 141 // This function iscalled from another thread.141 // This function may be called from another thread. 142 142 // Mutex protection for m_executionForbidden is needed to guarantee that the value is synchronized between processors, because 143 143 // if it were not, the worker could re-enter JSC::evaluate(), but with timeout already reset. … … 145 145 MutexLocker lock(m_sharedDataMutex); 146 146 m_executionForbidden = true; 147 m_globalData->terminator.terminateSoon(); 147 if (option == TerminateRunningScript) 148 m_globalData->terminator.terminateSoon(); 148 149 } 149 150 -
trunk/WebCore/bindings/js/WorkerScriptController.h
r49963 r57349 53 53 JSWorkerContext* workerContextWrapper() 54 54 { 55 if (m_executionForbidden) 56 return 0; 57 55 58 initScriptIfNeeded(); 56 59 return m_workerContextWrapper; … … 62 65 void setException(ScriptValue); 63 66 64 void forbidExecution(); 67 enum ForbidExecutionOption { TerminateRunningScript, LetRunningScriptFinish }; 68 void forbidExecution(ForbidExecutionOption); 65 69 66 70 JSC::JSGlobalData* globalData() { return m_globalData.get(); } -
trunk/WebCore/bindings/v8/WorkerScriptController.cpp
r56580 r57349 87 87 } 88 88 89 void WorkerScriptController::forbidExecution( )89 void WorkerScriptController::forbidExecution(ForbidExecutionOption option) 90 90 { 91 // This function iscalled from another thread.91 // This function may be called from another thread. 92 92 MutexLocker lock(m_sharedDataMutex); 93 93 m_executionForbidden = true; 94 v8::V8::TerminateExecution(); 94 if (option == TerminateRunningScript) 95 v8::V8::TerminateExecution(); 95 96 } 96 97 -
trunk/WebCore/bindings/v8/WorkerScriptController.h
r56580 r57349 56 56 void setException(ScriptValue); 57 57 58 void forbidExecution(); 58 enum ForbidExecutionOption { TerminateRunningScript, LetRunningScriptFinish }; 59 void forbidExecution(ForbidExecutionOption); 60 59 61 // Returns WorkerScriptController for the currently executing context. 0 will be returned if the current executing context is not the worker context. 60 62 static WorkerScriptController* controllerForContext(); -
trunk/WebCore/workers/DedicatedWorkerContext.cpp
r57068 r57349 63 63 void DedicatedWorkerContext::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, ExceptionCode& ec) 64 64 { 65 if (isClosing())66 return;67 65 // Disentangle the port in preparation for sending it to the remote context. 68 66 OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec); -
trunk/WebCore/workers/WorkerContext.cpp
r57210 r57349 61 61 namespace WebCore { 62 62 63 class CloseWorkerContextTask : public ScriptExecutionContext::Task { 64 public: 65 static PassOwnPtr<CloseWorkerContextTask> create() 66 { 67 return new CloseWorkerContextTask; 68 } 69 70 virtual void performTask(ScriptExecutionContext *context) 71 { 72 ASSERT(context->isWorkerContext()); 73 WorkerContext* workerContext = static_cast<WorkerContext*>(context); 74 // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop(). 75 workerContext->thread()->workerReportingProxy().workerContextClosed(); 76 } 77 78 virtual bool isCleanupTask() const { return true; } 79 }; 80 63 81 WorkerContext::WorkerContext(const KURL& url, const String& userAgent, WorkerThread* thread) 64 82 : m_url(url) … … 125 143 126 144 m_closing = true; 127 // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop(). 128 thread()->workerReportingProxy().workerContextClosed(); 145 // Let current script run to completion but prevent future script evaluations. 146 m_script->forbidExecution(WorkerScriptController::LetRunningScriptFinish); 147 postTask(CloseWorkerContextTask::create()); 129 148 } 130 149 -
trunk/WebCore/workers/WorkerThread.cpp
r55896 r57349 122 122 // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, 123 123 // forbidExecution() couldn't be called from stop(). 124 m_workerContext->script()->forbidExecution( );124 m_workerContext->script()->forbidExecution(WorkerScriptController::TerminateRunningScript); 125 125 } 126 126 } … … 219 219 // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever. 220 220 if (m_workerContext) { 221 m_workerContext->script()->forbidExecution( );221 m_workerContext->script()->forbidExecution(WorkerScriptController::TerminateRunningScript); 222 222 223 223 // FIXME: Rudely killing the thread won't work when we allow nested workers, because they will try to post notifications of their destruction.
Note: See TracChangeset
for help on using the changeset viewer.