summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-01 21:20:47 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-01 21:20:47 +0000
commitec775ef9b36dbcb5ebbd4fa550443bfa94c53a9f (patch)
tree5400ae2c5876e13aeeec2ab6ebcfc54f3f479840 /webkit
parent4b5d64ff3d7d95247ed4f078d8bf585a1726794d (diff)
downloadchromium_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.h3
-rw-r--r--webkit/glue/webworkerclient_impl.cc203
-rw-r--r--webkit/glue/webworkerclient_impl.h55
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