summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc8
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc65
-rw-r--r--chrome/browser/worker_host/worker_process_host.h23
-rw-r--r--chrome/browser/worker_host/worker_service.cc37
-rw-r--r--chrome/browser/worker_host/worker_service.h29
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h2
-rw-r--r--chrome/renderer/render_view.cc2
-rw-r--r--chrome/renderer/webworker_proxy.cc17
-rw-r--r--chrome/renderer/webworker_proxy.h11
-rw-r--r--chrome/worker/DEPS1
-rw-r--r--chrome/worker/worker_webkitclient_impl.cc7
-rw-r--r--chrome/worker/worker_webkitclient_impl.h1
-rw-r--r--webkit/glue/webkitclient_impl.h3
-rw-r--r--webkit/glue/webworkerclient_impl.cc203
-rw-r--r--webkit/glue/webworkerclient_impl.h55
17 files changed, 392 insertions, 78 deletions
diff --git a/DEPS b/DEPS
index 7318efc..1f25fd7 100644
--- a/DEPS
+++ b/DEPS
@@ -19,7 +19,7 @@ deps = {
"http://googletest.googlecode.com/svn/trunk@243",
"src/third_party/WebKit":
- "/trunk/deps/third_party/WebKit@15079",
+ "/trunk/deps/third_party/WebKit@15096",
"src/third_party/icu38":
"/trunk/deps/third_party/icu38@13472",
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 3fc0602..180b37a 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -193,6 +193,9 @@ void ResourceMessageFilter::OnChannelConnected(int32 peer_pid) {
// Hook AudioRendererHost to this object after channel is connected so it can
// this object for sending messages.
audio_renderer_host_->IPCChannelConnected(render_process_id_, handle(), this);
+
+ WorkerService::GetInstance()->Initialize(
+ resource_dispatcher_host_, ui_loop());
}
// Called on the IPC thread:
@@ -514,11 +517,12 @@ void ResourceMessageFilter::OnCreateDedicatedWorker(const GURL& url,
int* route_id) {
*route_id = render_widget_helper_->GetNextRoutingID();
WorkerService::GetInstance()->CreateDedicatedWorker(
- url, render_view_route_id, this, *route_id);
+ url, render_process_id_, render_view_route_id, this, render_process_id_,
+ *route_id);
}
void ResourceMessageFilter::OnForwardToWorker(const IPC::Message& message) {
- WorkerService::GetInstance()->ForwardMessage(message);
+ WorkerService::GetInstance()->ForwardMessage(message, render_process_id_);
}
void ResourceMessageFilter::OnDownloadUrl(const IPC::Message& message,
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index 4bb11ae..abf71d1 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -13,7 +13,6 @@
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
@@ -52,10 +51,13 @@ WorkerProcessHost::WorkerProcessHost(
}
WorkerProcessHost::~WorkerProcessHost() {
+ WorkerService::GetInstance()->NotifySenderShutdown(this);
+
// If we crashed, tell the RenderViewHost.
+ MessageLoop* ui_loop = WorkerService::GetInstance()->ui_loop();
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- i->filter->ui_loop()->PostTask(FROM_HERE, new WorkerCrashTask(
- i->filter->GetProcessId(), i->render_view_route_id));
+ ui_loop->PostTask(FROM_HERE, new WorkerCrashTask(
+ i->renderer_process_id, i->render_view_route_id));
}
}
@@ -71,6 +73,12 @@ bool WorkerProcessHost::Init() {
cmd_line.AppendSwitchWithValue(switches::kProcessType,
switches::kWorkerProcess);
cmd_line.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kWebWorkerShareProcesses)) {
+ cmd_line.AppendSwitch(switches::kWebWorkerShareProcesses);
+ }
+
base::ProcessHandle process;
#if defined(OS_WIN)
process = sandbox::StartProcess(&cmd_line);
@@ -85,25 +93,31 @@ bool WorkerProcessHost::Init() {
}
void WorkerProcessHost::CreateWorker(const GURL& url,
+ int renderer_process_id,
int render_view_route_id,
int worker_route_id,
- int renderer_route_id,
- ResourceMessageFilter* filter) {
+ IPC::Message::Sender* sender,
+ int sender_pid,
+ int sender_route_id) {
WorkerInstance instance;
instance.url = url;
+ instance.renderer_process_id = renderer_process_id;
instance.render_view_route_id = render_view_route_id;
instance.worker_route_id = worker_route_id;
- instance.renderer_route_id = renderer_route_id;
- instance.filter = filter;
+ instance.sender = sender;
+ instance.sender_pid = sender_pid;
+ instance.sender_route_id = sender_route_id;
instances_.push_back(instance);
Send(new WorkerProcessMsg_CreateWorker(url, worker_route_id));
UpdateTitle();
}
-bool WorkerProcessHost::FilterMessage(const IPC::Message& message) {
+bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
+ int sender_pid) {
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->renderer_route_id == message.routing_id()) {
+ if (i->sender_pid == sender_pid &&
+ i->sender_route_id == message.routing_id()) {
IPC::Message* new_message = new IPC::Message(message);
new_message->set_routing_id(i->worker_route_id);
Send(new_message);
@@ -121,11 +135,22 @@ URLRequestContext* WorkerProcessHost::GetRequestContext(
}
void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(WorkerProcessHost, message)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker,
+ OnCreateDedicatedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
+ OnForwardToWorker)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+ if (handled)
+ return;
+
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
if (i->worker_route_id == message.routing_id()) {
IPC::Message* new_message = new IPC::Message(message);
- new_message->set_routing_id(i->renderer_route_id);
- i->filter->Send(new_message);
+ new_message->set_routing_id(i->sender_route_id);
+ i->sender->Send(new_message);
if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
instances_.erase(i);
@@ -136,9 +161,9 @@ void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
}
}
-void WorkerProcessHost::RendererShutdown(ResourceMessageFilter* filter) {
+void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
- if (i->filter == filter) {
+ if (i->sender == sender) {
i = instances_.erase(i);
} else {
++i;
@@ -170,3 +195,17 @@ void WorkerProcessHost::UpdateTitle() {
set_name(ASCIIToWide(display_title));
}
+
+void WorkerProcessHost::OnCreateDedicatedWorker(const GURL& url,
+ int render_view_route_id,
+ int* route_id) {
+ DCHECK(instances_.size() == 1); // Only called when one process per worker.
+ *route_id = WorkerService::GetInstance()->next_worker_route_id();
+ WorkerService::GetInstance()->CreateDedicatedWorker(
+ url, instances_.front().renderer_process_id,
+ instances_.front().render_view_route_id, this, GetProcessId(), *route_id);
+}
+
+void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) {
+ WorkerService::GetInstance()->ForwardMessage(message, GetProcessId());
+}
diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h
index 5432396..5474724 100644
--- a/chrome/browser/worker_host/worker_process_host.h
+++ b/chrome/browser/worker_host/worker_process_host.h
@@ -12,8 +12,6 @@
#include "chrome/common/ipc_channel.h"
#include "googleurl/src/gurl.h"
-class ResourceMessageFilter;
-
class WorkerProcessHost : public ChildProcessHost {
public:
WorkerProcessHost(ResourceDispatcherHost* resource_dispatcher_host_);
@@ -24,16 +22,18 @@ class WorkerProcessHost : public ChildProcessHost {
// Creates a worker object in the process.
void CreateWorker(const GURL& url,
+ int renderer_process_id,
int render_view_route_id,
int worker_route_id,
- int renderer_route_id,
- ResourceMessageFilter* filter);
+ IPC::Message::Sender* sender,
+ int sender_pid,
+ int sender_route_id);
// Returns true iff the given message from a renderer process was forwarded to
// the worker.
- bool FilterMessage(const IPC::Message& message);
+ bool FilterMessage(const IPC::Message& message, int sender_pid);
- void RendererShutdown(ResourceMessageFilter* filter);
+ void SenderShutdown(IPC::Message::Sender* sender);
protected:
friend class WorkerService;
@@ -42,10 +42,12 @@ class WorkerProcessHost : public ChildProcessHost {
// between the renderer and worker processes.
struct WorkerInstance {
GURL url;
+ int renderer_process_id;
int render_view_route_id;
int worker_route_id;
- int renderer_route_id;
- ResourceMessageFilter* filter;
+ IPC::Message::Sender* sender;
+ int sender_pid;
+ int sender_route_id;
};
typedef std::list<WorkerInstance> Instances;
@@ -65,6 +67,11 @@ class WorkerProcessHost : public ChildProcessHost {
// Updates the title shown in the task manager.
void UpdateTitle();
+ void OnCreateDedicatedWorker(const GURL& url,
+ int render_view_route_id,
+ int* route_id);
+ void OnForwardToWorker(const IPC::Message& message);
+
Instances instances_;
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHost);
diff --git a/chrome/browser/worker_host/worker_service.cc b/chrome/browser/worker_host/worker_service.cc
index 49e25bc..a90c30e 100644
--- a/chrome/browser/worker_host/worker_service.cc
+++ b/chrome/browser/worker_host/worker_service.cc
@@ -25,7 +25,10 @@ WorkerService* WorkerService::GetInstance() {
return Singleton<WorkerService>::get();
}
-WorkerService::WorkerService() : next_worker_route_id_(0) {
+WorkerService::WorkerService()
+ : next_worker_route_id_(0),
+ resource_dispatcher_host_(NULL),
+ ui_loop_(NULL) {
// Receive a notification if the message filter is deleted.
NotificationService::current()->AddObserver(
this,
@@ -33,24 +36,33 @@ WorkerService::WorkerService() : next_worker_route_id_(0) {
NotificationService::AllSources());
}
+void WorkerService::Initialize(ResourceDispatcherHost* rdh,
+ MessageLoop* ui_loop) {
+ resource_dispatcher_host_ = rdh;
+ ui_loop_ = ui_loop;
+}
+
WorkerService::~WorkerService() {
}
bool WorkerService::CreateDedicatedWorker(const GURL &url,
+ int renderer_process_id,
int render_view_route_id,
- ResourceMessageFilter* filter,
- int renderer_route_id) {
+ IPC::Message::Sender* sender,
+ int sender_pid,
+ int sender_route_id) {
WorkerProcessHost* worker = NULL;
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWebWorkerProcessPerCore)) {
worker = GetProcessToFillUpCores();
- } else {
+ } else if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kWebWorkerShareProcesses)) {
worker = GetProcessForDomain(url);
}
if (!worker) {
- worker = new WorkerProcessHost(filter->resource_dispatcher_host());
+ worker = new WorkerProcessHost(resource_dispatcher_host_);
if (!worker->Init()) {
delete worker;
return false;
@@ -61,17 +73,19 @@ bool WorkerService::CreateDedicatedWorker(const GURL &url,
// unique among all worker processes. That way when the worker process sends
// a wrapped IPC message through us, we know which WorkerProcessHost to give
// it to.
- worker->CreateWorker(url, render_view_route_id, ++next_worker_route_id_,
- renderer_route_id, filter);
+ worker->CreateWorker(url, renderer_process_id, render_view_route_id,
+ next_worker_route_id(), sender, sender_pid,
+ sender_route_id);
return true;
}
-void WorkerService::ForwardMessage(const IPC::Message& message) {
+void WorkerService::ForwardMessage(const IPC::Message& message,
+ int sender_pid) {
for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
!iter.Done(); ++iter) {
WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- if (worker->FilterMessage(message))
+ if (worker->FilterMessage(message, sender_pid))
return;
}
@@ -131,10 +145,13 @@ void WorkerService::Observe(NotificationType type,
const NotificationDetails& details) {
DCHECK(type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN);
ResourceMessageFilter* filter = Source<ResourceMessageFilter>(source).ptr();
+ NotifySenderShutdown(filter);
+}
+void WorkerService::NotifySenderShutdown(IPC::Message::Sender* sender) {
for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
!iter.Done(); ++iter) {
WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- worker->RendererShutdown(filter);
+ worker->SenderShutdown(sender);
}
}
diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h
index cf18d58..0a88071 100644
--- a/chrome/browser/worker_host/worker_service.h
+++ b/chrome/browser/worker_host/worker_service.h
@@ -9,37 +9,46 @@
#include "base/basictypes.h"
#include "base/singleton.h"
+#include "chrome/common/ipc_message.h"
#include "chrome/common/notification_observer.h"
#include "googleurl/src/gurl.h"
-namespace IPC {
-class Message;
-}
class MessageLoop;
class WorkerProcessHost;
-class ResourceMessageFilter;
+class ResourceDispatcherHost;
class WorkerService : public NotificationObserver {
public:
// Returns the WorkerService singleton.
static WorkerService* GetInstance();
+ // Initialize the WorkerService. OK to be called multiple times.
+ void Initialize(ResourceDispatcherHost* rdh, MessageLoop* ui_loop);
+
// Creates a dedicated worker. Returns true on success.
bool CreateDedicatedWorker(const GURL &url,
+ int renderer_process_id,
int render_view_route_id,
- ResourceMessageFilter* filter,
- int renderer_route_id);
+ IPC::Message::Sender* sender,
+ int sender_pid,
+ int sender_route_id);
- // Called by ResourceMessageFilter when a message from the renderer comes that
- // should be forwarded to the worker process.
- void ForwardMessage(const IPC::Message& message);
+ // Called by the worker creator when a message arrives that should be
+ // forwarded to the worker process.
+ void ForwardMessage(const IPC::Message& message, int sender_pid);
// NotificationObserver interface.
void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
+ void NotifySenderShutdown(IPC::Message::Sender* sender);
+
+ MessageLoop* ui_loop() { return ui_loop_; }
+
+ int next_worker_route_id() { return ++next_worker_route_id_; }
+
private:
friend struct DefaultSingletonTraits<WorkerService>;
@@ -59,6 +68,8 @@ class WorkerService : public NotificationObserver {
WorkerProcessHost* GetLeastLoadedWorker();
int next_worker_route_id_;
+ ResourceDispatcherHost* resource_dispatcher_host_;
+ MessageLoop* ui_loop_;
DISALLOW_COPY_AND_ASSIGN(WorkerService);
};
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 0fb2a08..879d7b1 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -407,6 +407,10 @@ const wchar_t kEnableWebWorkers[] = L"enable-web-workers";
// Causes the worker process allocation to use as many processes as cores.
const wchar_t kWebWorkerProcessPerCore[] = L"web-worker-process-per-core";
+// Causes workers to run together in one process, depending on their domains.
+// Note this is duplicated in webworkerclient_impl.cc
+const wchar_t kWebWorkerShareProcesses[] = L"web-worker-share-processes";
+
// Enables experimental views under gtk.
const wchar_t kViewsGtk[] = L"views-gtk";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index c95634c..46dd746 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -154,8 +154,8 @@ extern const wchar_t kIPCUseFIFO[];
extern const wchar_t kEnableOutOfProcessDevTools[];
extern const wchar_t kEnableWebWorkers[];
-
extern const wchar_t kWebWorkerProcessPerCore[];
+extern const wchar_t kWebWorkerShareProcesses[];
extern const wchar_t kViewsGtk[];
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 4cf4fde..a8a8c41 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -1910,7 +1910,7 @@ void RenderView::OnMissingPluginStatus(WebPluginDelegate* delegate,
WebWorker* RenderView::CreateWebWorker(WebWorkerClient* client) {
#if defined(OS_WIN)
- return new WebWorkerProxy(client, routing_id_);
+ return new WebWorkerProxy(client, RenderThread::current(), routing_id_);
#else
// TODO(port): out of process workers
NOTIMPLEMENTED();
diff --git a/chrome/renderer/webworker_proxy.cc b/chrome/renderer/webworker_proxy.cc
index 5e553a2..60fcebb 100644
--- a/chrome/renderer/webworker_proxy.cc
+++ b/chrome/renderer/webworker_proxy.cc
@@ -4,9 +4,9 @@
#include "chrome/renderer/webworker_proxy.h"
+#include "chrome/common/child_thread.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/worker_messages.h"
-#include "chrome/renderer/render_thread.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "third_party/WebKit/WebKit/chromium/public/WebWorkerClient.h"
@@ -16,8 +16,10 @@ using WebKit::WebWorkerClient;
WebWorkerProxy::WebWorkerProxy(
WebWorkerClient* client,
+ ChildThread* child_thread,
int render_view_route_id)
: route_id_(MSG_ROUTING_NONE),
+ child_thread_(child_thread),
render_view_route_id_(render_view_route_id),
client_(client) {
}
@@ -29,13 +31,12 @@ void WebWorkerProxy::startWorkerContext(
const WebURL& script_url,
const WebString& user_agent,
const WebString& source_code) {
- RenderThread::current()->Send(
- new ViewHostMsg_CreateDedicatedWorker(
- script_url, render_view_route_id_, &route_id_));
+ child_thread_->Send(new ViewHostMsg_CreateDedicatedWorker(
+ script_url, render_view_route_id_, &route_id_));
if (route_id_ == MSG_ROUTING_NONE)
return;
- RenderThread::current()->AddRoute(route_id_, this);
+ child_thread_->AddRoute(route_id_, this);
Send(new WorkerMsg_StartWorkerContext(
route_id_, script_url, user_agent, source_code));
@@ -49,7 +50,7 @@ void WebWorkerProxy::startWorkerContext(
void WebWorkerProxy::terminateWorkerContext() {
if (route_id_ != MSG_ROUTING_NONE) {
Send(new WorkerMsg_TerminateWorkerContext(route_id_));
- RenderThread::current()->RemoveRoute(route_id_);
+ child_thread_->RemoveRoute(route_id_);
route_id_ = MSG_ROUTING_NONE;
}
}
@@ -60,8 +61,8 @@ void WebWorkerProxy::postMessageToWorkerContext(
}
void WebWorkerProxy::workerObjectDestroyed() {
- client_ = NULL;
Send(new WorkerMsg_WorkerObjectDestroyed(route_id_));
+ delete this;
}
bool WebWorkerProxy::Send(IPC::Message* message) {
@@ -75,7 +76,7 @@ bool WebWorkerProxy::Send(IPC::Message* message) {
// TODO(jabdelmalek): handle sync messages if we need them.
IPC::Message* wrapped_msg = new ViewHostMsg_ForwardToWorker(*message);
delete message;
- return RenderThread::current()->Send(wrapped_msg);
+ return child_thread_->Send(wrapped_msg);
}
void WebWorkerProxy::OnMessageReceived(const IPC::Message& message) {
diff --git a/chrome/renderer/webworker_proxy.h b/chrome/renderer/webworker_proxy.h
index 7bec251..7c44ba6 100644
--- a/chrome/renderer/webworker_proxy.h
+++ b/chrome/renderer/webworker_proxy.h
@@ -11,13 +11,10 @@
#include "chrome/common/ipc_channel.h"
#include "third_party/WebKit/WebKit/chromium/public/WebWorker.h"
+class ChildThread;
class GURL;
class RenderView;
-namespace IPC {
-class Message;
-}
-
// This class provides an implementation of WebWorker that the renderer provides
// to the glue. This class converts function calls to IPC messages that are
// dispatched in the worker process by WebWorkerClientProxy. It also receives
@@ -26,7 +23,9 @@ class Message;
class WebWorkerProxy : public WebKit::WebWorker,
public IPC::Channel::Listener {
public:
- WebWorkerProxy(WebKit::WebWorkerClient* client, int render_view_route_id);
+ WebWorkerProxy(WebKit::WebWorkerClient* client,
+ ChildThread* child_thread,
+ int render_view_route_id);
virtual ~WebWorkerProxy();
// WebWorker implementation.
@@ -46,6 +45,8 @@ class WebWorkerProxy : public WebKit::WebWorker,
// The routing id used to reach WebWorkerClientProxy in the worker process.
int route_id_;
+ ChildThread* child_thread_;
+
// The routing id for the RenderView that created this worker.
int render_view_route_id_;
diff --git a/chrome/worker/DEPS b/chrome/worker/DEPS
index 09e3a68..cf8be8e 100644
--- a/chrome/worker/DEPS
+++ b/chrome/worker/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+chrome/renderer",
"+chrome/worker",
"+sandbox/src",
"+webkit/glue",
diff --git a/chrome/worker/worker_webkitclient_impl.cc b/chrome/worker/worker_webkitclient_impl.cc
index 45a13e8..36d2be8 100644
--- a/chrome/worker/worker_webkitclient_impl.cc
+++ b/chrome/worker/worker_webkitclient_impl.cc
@@ -5,6 +5,8 @@
#include "chrome/worker/worker_webkitclient_impl.h"
#include "base/logging.h"
+#include "chrome/renderer/webworker_proxy.h"
+#include "chrome/worker/worker_thread.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
@@ -55,3 +57,8 @@ WebKit::WebString WorkerWebKitClientImpl::defaultLocale() {
NOTREACHED();
return WebKit::WebString();
}
+
+WebKit::WebWorker* WorkerWebKitClientImpl::CreateWebWorker(
+ WebKit::WebWorkerClient* client) {
+ return new WebWorkerProxy(client, WorkerThread::current(), 0);
+}
diff --git a/chrome/worker/worker_webkitclient_impl.h b/chrome/worker/worker_webkitclient_impl.h
index 474e1b2..061544c 100644
--- a/chrome/worker/worker_webkitclient_impl.h
+++ b/chrome/worker/worker_webkitclient_impl.h
@@ -23,6 +23,7 @@ class WorkerWebKitClientImpl : public webkit_glue::WebKitClientImpl {
const WebKit::WebURL& policy_url);
virtual void prefetchHostName(const WebKit::WebString&);
virtual WebKit::WebString defaultLocale();
+ virtual WebKit::WebWorker* CreateWebWorker(WebKit::WebWorkerClient* client);
};
#endif // CHROME_WORKER_WORKER_WEBKIT_CLIENT_IMPL_H_
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