diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-01 21:20:47 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-01 21:20:47 +0000 |
commit | ec775ef9b36dbcb5ebbd4fa550443bfa94c53a9f (patch) | |
tree | 5400ae2c5876e13aeeec2ab6ebcfc54f3f479840 /webkit | |
parent | 4b5d64ff3d7d95247ed4f078d8bf585a1726794d (diff) | |
download | chromium_src-ec775ef9b36dbcb5ebbd4fa550443bfa94c53a9f.zip chromium_src-ec775ef9b36dbcb5ebbd4fa550443bfa94c53a9f.tar.gz chromium_src-ec775ef9b36dbcb5ebbd4fa550443bfa94c53a9f.tar.bz2 |
Run workers in separate processes.
Review URL: http://codereview.chromium.org/99016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15098 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/webkitclient_impl.h | 3 | ||||
-rw-r--r-- | webkit/glue/webworkerclient_impl.cc | 203 | ||||
-rw-r--r-- | webkit/glue/webworkerclient_impl.h | 55 |
3 files changed, 241 insertions, 20 deletions
diff --git a/webkit/glue/webkitclient_impl.h b/webkit/glue/webkitclient_impl.h index 5b9882c..0f809dc 100644 --- a/webkit/glue/webkitclient_impl.h +++ b/webkit/glue/webkitclient_impl.h @@ -33,6 +33,9 @@ class WebKitClientImpl : public WebKit::WebKitClient { virtual void stopSharedTimer(); virtual void callOnMainThread(void (*func)()); virtual void suddenTerminationChanged(bool enabled) { } + virtual WebKit::WebWorker* CreateWebWorker(WebKit::WebWorkerClient* client) { + return NULL; + } private: void DoTimeout() { diff --git a/webkit/glue/webworkerclient_impl.cc b/webkit/glue/webworkerclient_impl.cc index add7eeb..05b7c55 100644 --- a/webkit/glue/webworkerclient_impl.cc +++ b/webkit/glue/webworkerclient_impl.cc @@ -10,19 +10,25 @@ #include "Frame.h" #include "FrameLoaderClient.h" +#include "GenericWorkerTask.h" #include "ScriptExecutionContext.h" #include "WorkerMessagingProxy.h" #include "Worker.h" +#include <wtf/Threading.h> #undef LOG #include "webkit/glue/webworkerclient_impl.h" +#include "base/command_line.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webframeloaderclient_impl.h" #include "webkit/glue/webframe_impl.h" #include "webkit/glue/webview_delegate.h" #include "webkit/glue/webview_impl.h" +#include "webkit/glue/webworker_impl.h" #include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" #include "third_party/WebKit/WebKit/chromium/public/WebScriptSource.h" #include "third_party/WebKit/WebKit/chromium/public/WebWorker.h" @@ -41,22 +47,35 @@ using WebKit::WebWorkerClient; // WebWorker object to talk to the worker process over IPC. The worker process // talks to WebCore::Worker* using WorkerObjectProxy, which we implement on // WebWorkerClientImpl. +// +// Note that if we're running each worker in a separate process, then nested +// workers end up using the same codepath as the renderer process. WebCore::WorkerContextProxy* WebCore::WorkerContextProxy::create( WebCore::Worker* worker) { - if (!worker->scriptExecutionContext()->isDocument()) + if (!worker->scriptExecutionContext()->isDocument() && + CommandLine::ForCurrentProcess()->HasSwitch( + L"web-worker-share-processes")) { return new WebCore::WorkerMessagingProxy(worker); + } + WebWorker* webworker = NULL; WebWorkerClientImpl* proxy = new WebWorkerClientImpl(worker); - // Get to the RenderView, so that we can tell the browser to create a - // worker process if necessary. - WebCore::Document* document = static_cast<WebCore::Document*>( - worker->scriptExecutionContext()); - WebFrameLoaderClient* frame_loader_client = - static_cast<WebFrameLoaderClient*>(document->frame()->loader()->client()); - WebViewDelegate* webview_delegate = - frame_loader_client->webframe()->webview_impl()->delegate(); - WebWorker* webworker = webview_delegate->CreateWebWorker(proxy); + if (worker->scriptExecutionContext()->isDocument()) { + // Get to the RenderView, so that we can tell the browser to create a + // worker process if necessary. + WebCore::Document* document = static_cast<WebCore::Document*>( + worker->scriptExecutionContext()); + WebFrameLoaderClient* frame_loader_client = + static_cast<WebFrameLoaderClient*>( + document->frame()->loader()->client()); + WebViewDelegate* webview_delegate = + frame_loader_client->webframe()->webview_impl()->delegate(); + webworker = webview_delegate->CreateWebWorker(proxy); + } else { + webworker = WebKit::webKitClient()->CreateWebWorker(proxy); + } + proxy->set_webworker(webworker); return proxy; } @@ -67,7 +86,8 @@ WebWorkerClientImpl::WebWorkerClientImpl(WebCore::Worker* worker) worker_(worker), asked_to_terminate_(false), unconfirmed_message_count_(0), - worker_context_had_pending_activity_(false) { + worker_context_had_pending_activity_(false), + worker_thread_id_(WTF::currentThread()) { } WebWorkerClientImpl::~WebWorkerClientImpl() { @@ -83,7 +103,14 @@ void WebWorkerClientImpl::startWorkerContext( const WebCore::String& source_code) { // Worker.terminate() could be called from JS before the context is started. if (asked_to_terminate_) - return; + return; + + if (!WTF::isMainThread()) { + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::createCallbackTask(&StartWorkerContextTask, this, + script_url.string(), user_agent, source_code)); + return; + } webworker_->startWorkerContext( webkit_glue::KURLToWebURL(script_url), @@ -93,9 +120,16 @@ void WebWorkerClientImpl::startWorkerContext( void WebWorkerClientImpl::terminateWorkerContext() { if (asked_to_terminate_) - return; + return; + asked_to_terminate_ = true; + if (!WTF::isMainThread()) { + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::createCallbackTask(&TerminateWorkerContextTask, this)); + return; + } + webworker_->terminateWorkerContext(); } @@ -103,26 +137,46 @@ void WebWorkerClientImpl::postMessageToWorkerContext( const WebCore::String& message) { // Worker.terminate() could be called from JS before the context is started. if (asked_to_terminate_) - return; + return; ++unconfirmed_message_count_; + + if (!WTF::isMainThread()) { + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::createCallbackTask(&PostMessageToWorkerContextTask, this, + message)); + return; + } + webworker_->postMessageToWorkerContext( webkit_glue::StringToWebString(message)); } bool WebWorkerClientImpl::hasPendingActivity() const { return !asked_to_terminate_ && - (unconfirmed_message_count_ || worker_context_had_pending_activity_); + (unconfirmed_message_count_ || worker_context_had_pending_activity_); } void WebWorkerClientImpl::workerObjectDestroyed() { - webworker_->workerObjectDestroyed(); + if (WTF::isMainThread()) { + webworker_->workerObjectDestroyed(); + worker_ = NULL; + } - // The lifetime of this proxy is controlled by the worker. - delete this; + // Even if this is called on the main thread, there could be a queued task for + // this object, so don't delete it right away. + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::createCallbackTask(&WorkerObjectDestroyedTask, this)); } void WebWorkerClientImpl::postMessageToWorkerObject(const WebString& message) { + if (WTF::currentThread() != worker_thread_id_) { + script_execution_context_->postTask( + WebCore::createCallbackTask(&PostMessageToWorkerObjectTask, this, + webkit_glue::WebStringToString(message))); + return; + } + worker_->dispatchMessage(webkit_glue::WebStringToString(message)); } @@ -130,6 +184,15 @@ void WebWorkerClientImpl::postExceptionToWorkerObject( const WebString& error_message, int line_number, const WebString& source_url) { + if (WTF::currentThread() != worker_thread_id_) { + script_execution_context_->postTask( + WebCore::createCallbackTask(&PostExceptionToWorkerObjectTask, this, + webkit_glue::WebStringToString(error_message), + line_number, + webkit_glue::WebStringToString(source_url))); + return; + } + script_execution_context_->reportException( webkit_glue::WebStringToString(error_message), line_number, @@ -143,6 +206,16 @@ void WebWorkerClientImpl::postConsoleMessageToWorkerObject( const WebString& message, int line_number, const WebString& source_url) { + if (WTF::currentThread() != worker_thread_id_) { + script_execution_context_->postTask( + WebCore::createCallbackTask(&PostConsoleMessageToWorkerObjectTask, this, + destination_id, source_id, message_level, + webkit_glue::WebStringToString(message), + line_number, + webkit_glue::WebStringToString(source_url))); + return; + } + script_execution_context_->addMessage( static_cast<WebCore::MessageDestination>(destination_id), static_cast<WebCore::MessageSource>(source_id), @@ -154,14 +227,104 @@ void WebWorkerClientImpl::postConsoleMessageToWorkerObject( void WebWorkerClientImpl::confirmMessageFromWorkerObject( bool has_pending_activity) { - --unconfirmed_message_count_; + // unconfirmed_message_count_ can only be updated on the thread where it's + // accessed. Otherwise there are race conditions with v8's garbage + // collection. + script_execution_context_->postTask( + WebCore::createCallbackTask(&ConfirmMessageFromWorkerObjectTask, this)); } void WebWorkerClientImpl::reportPendingActivity(bool has_pending_activity) { - worker_context_had_pending_activity_ = has_pending_activity; + // See above comment in confirmMessageFromWorkerObject. + script_execution_context_->postTask( + WebCore::createCallbackTask(&ReportPendingActivityTask, this, + has_pending_activity)); } void WebWorkerClientImpl::workerContextDestroyed() { } +void WebWorkerClientImpl::StartWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& script_url, + const WebCore::String& user_agent, + const WebCore::String& source_code) { + this_ptr->webworker_->startWorkerContext( + webkit_glue::KURLToWebURL(WebCore::KURL(script_url)), + webkit_glue::StringToWebString(user_agent), + webkit_glue::StringToWebString(source_code)); +} + +void WebWorkerClientImpl::TerminateWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr) { + this_ptr->webworker_->terminateWorkerContext(); +} + +void WebWorkerClientImpl::PostMessageToWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message) { + this_ptr->webworker_->postMessageToWorkerContext( + webkit_glue::StringToWebString(message)); +} + +void WebWorkerClientImpl::WorkerObjectDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr) { + if (this_ptr->worker_) // Check we haven't alread called this. + this_ptr->webworker_->workerObjectDestroyed(); + delete this_ptr; +} + +void WebWorkerClientImpl::PostMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message) { + if (this_ptr->worker_) + this_ptr->worker_->dispatchMessage(message); +} + +void WebWorkerClientImpl::PostExceptionToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url) { + this_ptr->script_execution_context_->reportException( + error_message, line_number, source_url); +} + +void WebWorkerClientImpl::PostConsoleMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + int destination_id, + int source_id, + int message_level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url) { + this_ptr->script_execution_context_->addMessage( + static_cast<WebCore::MessageDestination>(destination_id), + static_cast<WebCore::MessageSource>(source_id), + static_cast<WebCore::MessageLevel>(message_level), + message, + line_number, + source_url); +} + +void WebWorkerClientImpl::ConfirmMessageFromWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr) { + this_ptr->unconfirmed_message_count_--; +} + +void WebWorkerClientImpl::ReportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + bool has_pending_activity) { + this_ptr->worker_context_had_pending_activity_ = has_pending_activity; +} + #endif diff --git a/webkit/glue/webworkerclient_impl.h b/webkit/glue/webworkerclient_impl.h index 847b341..4e3f4ae 100644 --- a/webkit/glue/webworkerclient_impl.h +++ b/webkit/glue/webworkerclient_impl.h @@ -31,6 +31,9 @@ class WebWorkerClientImpl : public WebCore::WorkerContextProxy, void set_webworker(WebKit::WebWorker* webworker); // WebCore::WorkerContextProxy methods: + // These are called on the thread that created the worker. In the renderer + // process, this will be the main WebKit thread. In the worker process, this + // will be the thread of the executing worker (not the main WebKit thread). virtual void startWorkerContext(const WebCore::KURL& script_url, const WebCore::String& user_agent, const WebCore::String& source_code); @@ -40,6 +43,7 @@ class WebWorkerClientImpl : public WebCore::WorkerContextProxy, virtual void workerObjectDestroyed(); // WebWorkerClient methods: + // These are called on the main WebKit thread. virtual void postMessageToWorkerObject(const WebKit::WebString& message); virtual void postExceptionToWorkerObject( const WebKit::WebString& error_message, @@ -59,6 +63,56 @@ class WebWorkerClientImpl : public WebCore::WorkerContextProxy, private: virtual ~WebWorkerClientImpl(); + // Methods used to support WebWorkerClientImpl being constructed on worker + // threads. + // These tasks are dispatched on the WebKit thread. + static void StartWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& script_url, + const WebCore::String& user_agent, + const WebCore::String& source_code); + static void TerminateWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr); + static void PostMessageToWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message); + static void WorkerObjectDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr); + + // These tasks are dispatched on the thread that created the worker (i.e. + // main WebKit thread in renderer process, and the worker thread in the worker + // process). + static void PostMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message); + static void PostExceptionToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url); + static void PostConsoleMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + int destination_id, + int source_id, + int message_level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url); + static void ConfirmMessageFromWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr); + static void ReportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + bool has_pending_activity); + // Guard against context from being destroyed before a worker exits. WTF::RefPtr<WebCore::ScriptExecutionContext> script_execution_context_; @@ -67,6 +121,7 @@ class WebWorkerClientImpl : public WebCore::WorkerContextProxy, bool asked_to_terminate_; uint32 unconfirmed_message_count_; bool worker_context_had_pending_activity_; + WTF::ThreadIdentifier worker_thread_id_; }; #endif |