diff options
-rw-r--r-- | DEPS | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 8 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.cc | 65 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.h | 23 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_service.cc | 37 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_service.h | 29 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 2 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 2 | ||||
-rw-r--r-- | chrome/renderer/webworker_proxy.cc | 17 | ||||
-rw-r--r-- | chrome/renderer/webworker_proxy.h | 11 | ||||
-rw-r--r-- | chrome/worker/DEPS | 1 | ||||
-rw-r--r-- | chrome/worker/worker_webkitclient_impl.cc | 7 | ||||
-rw-r--r-- | chrome/worker/worker_webkitclient_impl.h | 1 | ||||
-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 |
17 files changed, 392 insertions, 78 deletions
@@ -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 |