summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-04 02:00:56 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-04 02:00:56 +0000
commita5da6d613f41ecf35c027e8744dd6d3a41e4010c (patch)
treedad6a3e159fcc21df62180f481a0024db97d5b0d /chrome
parente23ed5427d0892d07480781f45b4367adebc0c00 (diff)
downloadchromium_src-a5da6d613f41ecf35c027e8744dd6d3a41e4010c.zip
chromium_src-a5da6d613f41ecf35c027e8744dd6d3a41e4010c.tar.gz
chromium_src-a5da6d613f41ecf35c027e8744dd6d3a41e4010c.tar.bz2
Cross-process Message Port implementation.
I'm sending this first, then I'll add support to workers in another changelist to avoid making this change larger. TEST=running message port related layout tests in ui_tests Review URL: http://codereview.chromium.org/159372 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22356 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/in_process_webkit/browser_webkitclient_impl.cc6
-rw-r--r--chrome/browser/in_process_webkit/browser_webkitclient_impl.h1
-rw-r--r--chrome/browser/renderer_host/render_sandbox_host_linux.cc4
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc45
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h4
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.cc225
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.h90
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc44
-rw-r--r--chrome/browser/worker_host/worker_process_host.h4
-rw-r--r--chrome/browser/worker_host/worker_service.cc24
-rw-r--r--chrome/browser/worker_host/worker_service.h28
-rw-r--r--chrome/chrome.gyp4
-rw-r--r--chrome/common/notification_type.h4
-rw-r--r--chrome/common/webmessageportchannel_impl.cc204
-rw-r--r--chrome/common/webmessageportchannel_impl.h73
-rw-r--r--chrome/common/worker_messages.h2
-rw-r--r--chrome/common/worker_messages_internal.h58
-rw-r--r--chrome/renderer/renderer_webkitclient_impl.cc6
-rw-r--r--chrome/renderer/renderer_webkitclient_impl.h1
-rw-r--r--chrome/worker/worker_uitest.cc29
-rw-r--r--chrome/worker/worker_webkitclient_impl.cc6
-rw-r--r--chrome/worker/worker_webkitclient_impl.h1
22 files changed, 803 insertions, 60 deletions
diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
index 96119b4..e1052db 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
@@ -36,6 +36,12 @@ bool BrowserWebKitClientImpl::isLinkVisited(unsigned long long link_hash) {
return false;
}
+WebKit::WebMessagePortChannel*
+BrowserWebKitClientImpl::createMessagePortChannel() {
+ NOTREACHED();
+ return NULL;
+}
+
void BrowserWebKitClientImpl::setCookies(const WebKit::WebURL& url,
const WebKit::WebURL& policy_url,
const WebKit::WebString& value) {
diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
index 68b4243..61dffa6 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
@@ -16,6 +16,7 @@ class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl {
virtual unsigned long long visitedLinkHash(const char* canonicalURL,
size_t length);
virtual bool isLinkVisited(unsigned long long linkHash);
+ virtual WebKit::WebMessagePortChannel* createMessagePortChannel();
virtual void setCookies(const WebKit::WebURL& url,
const WebKit::WebURL& policy_url,
const WebKit::WebString& value);
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
index 6b274f1..7611df0 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
@@ -124,6 +124,10 @@ class SandboxIPCProcess : public WebKitClient {
virtual unsigned long long visitedLinkHash(const char*, size_t) { return 0; }
virtual bool isLinkVisited(unsigned long long) { return false; }
+ virtual WebKit::WebMessagePortChannel* createMessagePortChannel() {
+ return NULL;
+ }
+
virtual void setCookies(const WebURL&, const WebURL&, const WebString&) { }
virtual WebString cookies(const WebURL&, const WebURL&) { return WebString(); }
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index be61cf3..c726591 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -26,6 +26,7 @@
#include "chrome/browser/renderer_host/file_system_accessor.h"
#include "chrome/browser/renderer_host/render_widget_helper.h"
#include "chrome/browser/spellchecker.h"
+#include "chrome/browser/worker_host/message_port_dispatcher.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/app_cache/app_cache_dispatcher_host.h"
#include "chrome/common/chrome_plugin_lib.h"
@@ -37,6 +38,7 @@
#include "chrome/common/pref_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
+#include "chrome/common/worker_messages.h"
#include "net/base/mime_util.h"
#include "net/base/load_flags.h"
#include "net/http/http_cache.h"
@@ -158,7 +160,9 @@ ResourceMessageFilter::ResourceMessageFilter(
resource_dispatcher_host->webkit_thread()))),
ALLOW_THIS_IN_INITIALIZER_LIST(db_dispatcher_host_(
new DatabaseDispatcherHost(profile->GetPath(), this))),
- off_the_record_(profile->IsOffTheRecord()) {
+ off_the_record_(profile->IsOffTheRecord()),
+ next_route_id_(NewCallbackWithReturnValue(
+ render_widget_helper, &RenderWidgetHelper::GetNextRoutingID)) {
DCHECK(request_context_.get());
DCHECK(request_context_->cookie_store());
DCHECK(media_request_context_.get());
@@ -244,22 +248,21 @@ void ResourceMessageFilter::OnChannelClosing() {
}
// Called on the IPC thread:
-bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
+bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+ MessagePortDispatcher* mp_dispatcher = MessagePortDispatcher::GetInstance();
bool msg_is_ok = true;
- bool handled = resource_dispatcher_host_->OnMessageReceived(
- message, this, &msg_is_ok) ||
- app_cache_dispatcher_host_->OnMessageReceived(
- message, &msg_is_ok) ||
- dom_storage_dispatcher_host_->OnMessageReceived(
- message, &msg_is_ok) ||
- audio_renderer_host_->OnMessageReceived(
- message, &msg_is_ok) ||
- db_dispatcher_host_->OnMessageReceived(message, &msg_is_ok);
+ bool handled =
+ resource_dispatcher_host_->OnMessageReceived(msg, this, &msg_is_ok) ||
+ app_cache_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
+ dom_storage_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
+ audio_renderer_host_->OnMessageReceived(msg, &msg_is_ok) ||
+ db_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
+ mp_dispatcher->OnMessageReceived(msg, this, next_route_id_, &msg_is_ok);
if (!handled) {
DCHECK(msg_is_ok); // It should have been marked handled if it wasn't OK.
handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(ResourceMessageFilter, message, msg_is_ok)
+ IPC_BEGIN_MESSAGE_MAP_EX(ResourceMessageFilter, msg, msg_is_ok)
// On Linux we need to dispatch these messages to the UI2 thread
// because we cannot make X calls from the IO thread. Mac
// doesn't have windowed plug-ins so we handle the messages in
@@ -288,7 +291,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginPath, OnGetPluginPath)
IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ContextMenu,
- OnReceiveContextMenuMsg(message))
+ OnReceiveContextMenuMsg(msg))
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPlugin,
OnOpenChannelToPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker,
@@ -304,12 +307,11 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms,
OnRendererHistograms)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_PaintRect,
- render_widget_helper_->DidReceivePaintMsg(message))
+ render_widget_helper_->DidReceivePaintMsg(msg))
IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync,
OnClipboardWriteObjects)
IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsSync,
OnClipboardWriteObjects)
-
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardIsFormatAvailable,
OnClipboardIsFormatAvailable)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadText,
@@ -318,7 +320,6 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnClipboardReadAsciiText)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadHTML,
OnClipboardReadHTML)
-
IPC_MESSAGE_HANDLER(ViewHostMsg_GetMimeTypeFromExtension,
OnGetMimeTypeFromExtension)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetMimeTypeFromFile,
@@ -344,14 +345,11 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToExtension,
OnOpenChannelToExtension)
- IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToTab,
- OnOpenChannelToTab)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToTab, OnOpenChannelToTab)
IPC_MESSAGE_HANDLER(ViewHostMsg_CloseIdleConnections,
OnCloseIdleConnections)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode,
- OnSetCacheMode)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize,
- OnGetFileSize)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode, OnSetCacheMode)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, OnGetFileSize)
IPC_MESSAGE_UNHANDLED(
handled = false)
@@ -359,8 +357,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
}
if (!msg_is_ok) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(message.type(),
- handle());
+ BrowserRenderProcessHost::BadMessageTerminateProcess(msg.type(), handle());
}
return handled;
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index ee92565..cf84dfc 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -15,6 +15,7 @@
#include "base/ref_counted.h"
#include "base/shared_memory.h"
#include "base/string16.h"
+#include "base/task.h"
#include "build/build_config.h"
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
#include "chrome/browser/renderer_host/render_widget_helper.h"
@@ -317,6 +318,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
// Whether this process is used for off the record tabs.
bool off_the_record_;
+ // A callback to create a routing id for the associated renderer process.
+ CallbackWithReturnValue<int>::Type* next_route_id_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceMessageFilter);
};
diff --git a/chrome/browser/worker_host/message_port_dispatcher.cc b/chrome/browser/worker_host/message_port_dispatcher.cc
new file mode 100644
index 0000000..9804e86
--- /dev/null
+++ b/chrome/browser/worker_host/message_port_dispatcher.cc
@@ -0,0 +1,225 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/worker_host/message_port_dispatcher.h"
+
+#include "base/singleton.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/worker_host/worker_process_host.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/worker_messages.h"
+
+
+MessagePortDispatcher* MessagePortDispatcher::GetInstance() {
+ return Singleton<MessagePortDispatcher>::get();
+}
+
+MessagePortDispatcher::MessagePortDispatcher()
+ : next_message_port_id_(0),
+ sender_(NULL),
+ next_routing_id_(NULL) {
+ // Receive a notification if a message filter or WorkerProcessHost is deleted.
+ registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
+ NotificationService::AllSources());
+
+ registrar_.Add(this, NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
+ NotificationService::AllSources());
+}
+
+MessagePortDispatcher::~MessagePortDispatcher() {
+}
+
+bool MessagePortDispatcher::OnMessageReceived(
+ const IPC::Message& message,
+ IPC::Message::Sender* sender,
+ CallbackWithReturnValue<int>::Type* next_routing_id,
+ bool* message_was_ok) {
+ sender_ = sender;
+ next_routing_id_ = next_routing_id;
+
+ bool handled = true;
+ *message_was_ok = true;
+
+ IPC_BEGIN_MESSAGE_MAP_EX(MessagePortDispatcher, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_CreateMessagePort, OnCreate)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_DestroyMessagePort, OnDestroy)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_Entangle, OnEntangle)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_PostMessage, OnPostMessage)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_QueueMessages, OnQueueMessages)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_SendQueuedMessages,
+ OnSendQueuedMessages)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+
+ sender_ = NULL;
+ next_routing_id_ = NULL;
+
+ return handled;
+}
+
+bool MessagePortDispatcher::Send(IPC::Message* message) {
+ return sender_->Send(message);
+}
+
+void MessagePortDispatcher::OnCreate(int *route_id,
+ int* message_port_id) {
+ *message_port_id = ++next_message_port_id_;
+ *route_id = next_routing_id_->Run();
+
+ MessagePort port;
+ port.sender = sender_;
+ port.route_id = *route_id;
+ port.next_routing_id = next_routing_id_;
+ port.message_port_id = *message_port_id;
+ port.entangled_message_port_id = MSG_ROUTING_NONE;
+ port.queue_messages = false;
+ message_ports_[*message_port_id] = port;
+}
+
+void MessagePortDispatcher::OnDestroy(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(message_ports_[message_port_id].queued_messages.empty());
+ delete message_ports_[message_port_id].next_routing_id;
+ message_ports_.erase(message_port_id);
+}
+
+void MessagePortDispatcher::OnEntangle(int local_message_port_id,
+ int remote_message_port_id) {
+ if (!message_ports_.count(local_message_port_id) ||
+ !message_ports_.count(remote_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
+ MSG_ROUTING_NONE);
+ message_ports_[remote_message_port_id].entangled_message_port_id =
+ local_message_port_id;
+}
+
+void MessagePortDispatcher::OnPostMessage(int sender_message_port_id,
+ const string16& message,
+ int sent_message_port_id) {
+ if (!message_ports_.count(sender_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ int entangled_message_port_id =
+ message_ports_[sender_message_port_id].entangled_message_port_id;
+ if (entangled_message_port_id == MSG_ROUTING_NONE)
+ return; // Process could have crashed.
+
+ if (!message_ports_.count(entangled_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ PostMessageTo(entangled_message_port_id, message, sent_message_port_id);
+}
+
+void MessagePortDispatcher::PostMessageTo(int message_port_id,
+ const string16& message,
+ int sent_message_port_id) {
+ if (!message_ports_.count(message_port_id) ||
+ (sent_message_port_id != MSG_ROUTING_NONE &&
+ !message_ports_.count(sent_message_port_id))) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& entangled_port = message_ports_[message_port_id];
+
+ MessagePort* sent_port = NULL;
+ if (sent_message_port_id != MSG_ROUTING_NONE) {
+ sent_port = &message_ports_[sent_message_port_id];
+ sent_port->queue_messages = true;
+ }
+
+ if (entangled_port.queue_messages) {
+ entangled_port.queued_messages.push_back(
+ std::make_pair(message, sent_message_port_id));
+ } else {
+ // If a message port was sent around, the new location will need a routing
+ // id. Instead of having the created port send us a sync message to get it,
+ // send along with the message.
+ int new_routing_id = MSG_ROUTING_NONE;
+ if (sent_message_port_id != MSG_ROUTING_NONE) {
+ new_routing_id = entangled_port.next_routing_id->Run();
+ sent_port->sender = entangled_port.sender;
+
+ // Update the entry for the sent port as it can be in a different process.
+ sent_port->route_id = new_routing_id;
+ }
+
+ // Now send the message to the entangled port.
+ IPC::Message* ipc_msg = new WorkerProcessMsg_Message(
+ entangled_port.route_id, message, sent_message_port_id,
+ new_routing_id);
+ entangled_port.sender->Send(ipc_msg);
+ }
+}
+
+void MessagePortDispatcher::OnQueueMessages(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ port.queue_messages = true;
+ port.sender->Send(new WorkerProcessMsg_MessagesQueued(port.route_id));
+}
+
+void MessagePortDispatcher::OnSendQueuedMessages(
+ int message_port_id,
+ const QueuedMessages& queued_messages) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ // Send the queued messages to the port again. This time they'll reach the
+ // new location.
+ MessagePort& port = message_ports_[message_port_id];
+ port.queue_messages = false;
+ port.queued_messages.insert(port.queued_messages.begin(),
+ queued_messages.begin(),
+ queued_messages.end());
+ for (QueuedMessages::iterator iter = port.queued_messages.begin();
+ iter != port.queued_messages.end(); ++iter) {
+ PostMessageTo(message_port_id, iter->first, iter->second);
+ }
+ port.queued_messages.clear();
+}
+
+void MessagePortDispatcher::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ IPC::Message::Sender* sender = NULL;
+ if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
+ sender = Source<ResourceMessageFilter>(source).ptr();
+ } else if (type.value == NotificationType::WORKER_PROCESS_HOST_SHUTDOWN) {
+ sender = Source<WorkerProcessHost>(source).ptr();
+ } else {
+ NOTREACHED();
+ }
+
+ // Check if the (possibly) crashed process had any message ports.
+ for (MessagePorts::iterator iter = message_ports_.begin();
+ iter != message_ports_.end();) {
+ MessagePorts::iterator cur_item = iter++;
+ if (cur_item->second.sender == sender) {
+ if (cur_item->second.entangled_message_port_id != MSG_ROUTING_NONE) {
+ message_ports_[cur_item->second.entangled_message_port_id].
+ entangled_message_port_id = MSG_ROUTING_NONE;
+ }
+ message_ports_.erase(cur_item);
+ }
+ }
+}
diff --git a/chrome/browser/worker_host/message_port_dispatcher.h b/chrome/browser/worker_host/message_port_dispatcher.h
new file mode 100644
index 0000000..d443b07
--- /dev/null
+++ b/chrome/browser/worker_host/message_port_dispatcher.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
+#define CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/task.h"
+#include "chrome/common/notification_registrar.h"
+#include "ipc/ipc_message.h"
+
+class MessagePortDispatcher : public NotificationObserver {
+ public:
+ typedef std::vector<std::pair<string16, int> > QueuedMessages;
+
+ // Returns the MessagePortDispatcher singleton.
+ static MessagePortDispatcher* GetInstance();
+
+ bool OnMessageReceived(const IPC::Message& message,
+ IPC::Message::Sender* sender,
+ CallbackWithReturnValue<int>::Type* next_routing_id,
+ bool* message_was_ok);
+
+ bool Send(IPC::Message* message);
+
+ private:
+ friend struct DefaultSingletonTraits<MessagePortDispatcher>;
+
+ MessagePortDispatcher();
+ ~MessagePortDispatcher();
+
+ // Message handlers.
+ void OnCreate(int* route_id, int* message_port_id);
+ void OnDestroy(int message_port_id);
+ void OnEntangle(int local_message_port_id, int remote_message_port_id);
+ void OnPostMessage(int sender_message_port_id,
+ const string16& message,
+ int sent_message_port_id);
+ void OnQueueMessages(int message_port_id);
+ void OnSendQueuedMessages(int message_port_id,
+ const QueuedMessages& queued_messages);
+
+ void PostMessageTo(int message_port_id,
+ const string16& message,
+ int sent_message_port_id);
+
+ // NotificationObserver interface.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ struct MessagePort {
+ // sender and route_id are what we need to send messages to the port.
+ IPC::Message::Sender* sender;
+ int route_id;
+ // A function pointer to generate a new route id for the sender above.
+ // Owned by "sender" above, so don't delete.
+ CallbackWithReturnValue<int>::Type* next_routing_id;
+ // A globally unique id for this message port.
+ int message_port_id;
+ // The globally unique id of the entangled message port.
+ int entangled_message_port_id;
+ // If true, all messages to this message port are queued and not delivered.
+ bool queue_messages;
+ QueuedMessages queued_messages;
+ };
+
+ typedef std::map<int, MessagePort> MessagePorts;
+ MessagePorts message_ports_;
+
+ // We need globally unique identifiers for each message port.
+ int next_message_port_id_;
+
+ // Valid only during IPC message dispatching.
+ IPC::Message::Sender* sender_;
+ CallbackWithReturnValue<int>::Type* next_routing_id_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePortDispatcher);
+};
+
+#endif // CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index bcb3da2..ed3fd9f 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -18,11 +18,14 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/worker_host/message_port_dispatcher.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/result_codes.h"
#include "chrome/common/worker_messages.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_switches.h"
@@ -59,11 +62,16 @@ class WorkerCrashTask : public Task {
WorkerProcessHost::WorkerProcessHost(
ResourceDispatcherHost* resource_dispatcher_host_)
: ChildProcessHost(WORKER_PROCESS, resource_dispatcher_host_) {
+ next_route_id_ = NewCallbackWithReturnValue(
+ WorkerService::GetInstance(), &WorkerService::next_worker_route_id);
}
WorkerProcessHost::~WorkerProcessHost() {
- WorkerService::GetInstance()->OnSenderShutdown(this);
- WorkerService::GetInstance()->OnWorkerProcessDestroyed(this);
+ // Let interested observers know we are being deleted.
+ NotificationService::current()->Notify(
+ NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
+ Source<WorkerProcessHost>(this),
+ NotificationService::NoDetails());
// If we crashed, tell the RenderViewHost.
MessageLoop* ui_loop = WorkerService::GetInstance()->ui_loop();
@@ -157,16 +165,28 @@ 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_CancelCreateDedicatedWorker,
- OnCancelCreateDedicatedWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
- OnForwardToWorker)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP_EX()
+ bool msg_is_ok = true;
+ bool handled = MessagePortDispatcher::GetInstance()->OnMessageReceived(
+ message, this, next_route_id_, &msg_is_ok);
+
+ if (!handled) {
+ handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker,
+ OnCreateDedicatedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
+ OnCancelCreateDedicatedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
+ OnForwardToWorker)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+ }
+
+ if (!msg_is_ok) {
+ NOTREACHED();
+ base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
+ }
+
if (handled)
return;
diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h
index 00a6642..44bc676 100644
--- a/chrome/browser/worker_host/worker_process_host.h
+++ b/chrome/browser/worker_host/worker_process_host.h
@@ -8,6 +8,7 @@
#include <list>
#include "base/basictypes.h"
+#include "base/task.h"
#include "chrome/common/child_process_host.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_channel.h"
@@ -69,6 +70,9 @@ class WorkerProcessHost : public ChildProcessHost {
Instances instances_;
+ // A callback to create a routing id for the associated worker process.
+ CallbackWithReturnValue<int>::Type* next_route_id_;
+
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHost);
};
diff --git a/chrome/browser/worker_host/worker_service.cc b/chrome/browser/worker_host/worker_service.cc
index e67ae80..df8ba51 100644
--- a/chrome/browser/worker_host/worker_service.cc
+++ b/chrome/browser/worker_host/worker_service.cc
@@ -10,9 +10,9 @@
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/worker_messages.h"
@@ -30,9 +30,12 @@ WorkerService::WorkerService()
: next_worker_route_id_(0),
resource_dispatcher_host_(NULL),
ui_loop_(NULL) {
- // Receive a notification if the message filter is deleted.
+ // Receive a notification if a message filter or WorkerProcessHost is deleted.
registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
NotificationService::AllSources());
+
+ registrar_.Add(this, NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
+ NotificationService::AllSources());
}
void WorkerService::Initialize(ResourceDispatcherHost* rdh,
@@ -210,12 +213,19 @@ bool WorkerService::CanCreateWorkerProcess(
void WorkerService::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN);
- ResourceMessageFilter* filter = Source<ResourceMessageFilter>(source).ptr();
- OnSenderShutdown(filter);
+ if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
+ ResourceMessageFilter* sender = Source<ResourceMessageFilter>(source).ptr();
+ SenderShutdown(sender);
+ } else if (type.value == NotificationType::WORKER_PROCESS_HOST_SHUTDOWN) {
+ WorkerProcessHost* sender = Source<WorkerProcessHost>(source).ptr();
+ SenderShutdown(sender);
+ WorkerProcessDestroyed(sender);
+ } else {
+ NOTREACHED();
+ }
}
-void WorkerService::OnSenderShutdown(IPC::Message::Sender* sender) {
+void WorkerService::SenderShutdown(IPC::Message::Sender* sender) {
for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
!iter.Done(); ++iter) {
WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
@@ -233,7 +243,7 @@ void WorkerService::OnSenderShutdown(IPC::Message::Sender* sender) {
}
}
-void WorkerService::OnWorkerProcessDestroyed(WorkerProcessHost* process) {
+void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
if (queued_workers_.empty())
return;
diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h
index 45e8248..704a7da 100644
--- a/chrome/browser/worker_host/worker_service.h
+++ b/chrome/browser/worker_host/worker_service.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_WORKER_HOST__WORKER_SERVICE_H_
-#define CHROME_BROWSER_WORKER_HOST__WORKER_SERVICE_H_
+#ifndef CHROME_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
+#define CHROME_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
#include <list>
@@ -42,17 +42,6 @@ class WorkerService : public NotificationObserver {
// 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);
-
- // Notifies us that a process that's talking to a worker has shut down.
- void OnSenderShutdown(IPC::Message::Sender* sender);
-
- // Notifies us that a worker process has closed.
- void OnWorkerProcessDestroyed(WorkerProcessHost* process);
-
MessageLoop* ui_loop() { return ui_loop_; }
int next_worker_route_id() { return ++next_worker_route_id_; }
@@ -86,6 +75,17 @@ class WorkerService : public NotificationObserver {
// we're using a strategy of one process per core.
bool CanCreateWorkerProcess(const WorkerProcessHost::WorkerInstance& instance);
+ // NotificationObserver interface.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Notifies us that a process that's talking to a worker has shut down.
+ void SenderShutdown(IPC::Message::Sender* sender);
+
+ // Notifies us that a worker process has closed.
+ void WorkerProcessDestroyed(WorkerProcessHost* process);
+
NotificationRegistrar registrar_;
int next_worker_route_id_;
ResourceDispatcherHost* resource_dispatcher_host_;
@@ -96,4 +96,4 @@ class WorkerService : public NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(WorkerService);
};
-#endif // CHROME_BROWSER_WORKER_HOST__WORKER_SERVICE_H_
+#endif // CHROME_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index de83502..4edef2fb 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -486,6 +486,8 @@
'common/visitedlink_common.cc',
'common/visitedlink_common.h',
'common/webkit_param_traits.h',
+ 'common/webmessageportchannel_impl.cc',
+ 'common/webmessageportchannel_impl.h',
'common/win_safe_util.cc',
'common/win_safe_util.h',
'common/worker_messages.h',
@@ -1901,6 +1903,8 @@
'browser/window_sizer_mac.mm',
'browser/window_sizer_linux.cc',
'browser/window_sizer_win.cc',
+ 'browser/worker_host/message_port_dispatcher.cc',
+ 'browser/worker_host/message_port_dispatcher.h',
'browser/worker_host/worker_process_host.cc',
'browser/worker_host/worker_process_host.h',
'browser/worker_host/worker_service.cc',
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index ad99d89..7a95f9a 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -169,6 +169,10 @@ class NotificationType {
// twice).
RESOURCE_MESSAGE_FILTER_SHUTDOWN,
+ // Lets interested observers know when a WorkerProcessHost is being deleted
+ // and can no longer be used.
+ WORKER_PROCESS_HOST_SHUTDOWN,
+
// Views -------------------------------------------------------------------
// Notification that a view was removed from a view hierarchy. The source
diff --git a/chrome/common/webmessageportchannel_impl.cc b/chrome/common/webmessageportchannel_impl.cc
new file mode 100644
index 0000000..a165db8
--- /dev/null
+++ b/chrome/common/webmessageportchannel_impl.cc
@@ -0,0 +1,204 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/webmessageportchannel_impl.h"
+
+#include "chrome/common/child_process.h"
+#include "chrome/common/child_thread.h"
+#include "chrome/common/worker_messages.h"
+#include "webkit/api/public/WebString.h"
+#include "webkit/api/public/WebMessagePortChannelClient.h"
+
+using WebKit::WebMessagePortChannel;
+using WebKit::WebMessagePortChannelClient;
+using WebKit::WebString;
+
+WebMessagePortChannelImpl::WebMessagePortChannelImpl()
+ : client_(NULL),
+ route_id_(MSG_ROUTING_NONE),
+ message_port_id_(MSG_ROUTING_NONE) {
+ AddRef();
+ Init();
+}
+
+WebMessagePortChannelImpl::WebMessagePortChannelImpl(
+ int route_id,
+ int message_port_id)
+ : client_(NULL),
+ route_id_(route_id),
+ message_port_id_(message_port_id) {
+ AddRef();
+ Init();
+}
+
+WebMessagePortChannelImpl::~WebMessagePortChannelImpl() {
+ if (message_port_id_ != MSG_ROUTING_NONE)
+ Send(new WorkerProcessHostMsg_DestroyMessagePort(message_port_id_));
+
+ if (route_id_ != MSG_ROUTING_NONE)
+ ChildThread::current()->RemoveRoute(route_id_);
+}
+
+void WebMessagePortChannelImpl::setClient(WebMessagePortChannelClient* client) {
+ // Must lock here since client_ is called on the main thread.
+ AutoLock auto_lock(lock_);
+ client_ = client;
+}
+
+void WebMessagePortChannelImpl::destroy() {
+ setClient(NULL);
+ Release();
+}
+
+void WebMessagePortChannelImpl::entangle(WebMessagePortChannel* channel) {
+ // The message port ids might not be set up yet, if this channel wasn't
+ // created on the main thread. So need to wait until we're on the main thread
+ // before getting the other message port id.
+ scoped_refptr<WebMessagePortChannelImpl> webchannel =
+ static_cast<WebMessagePortChannelImpl*>(channel);
+ Entangle(webchannel);
+}
+
+void WebMessagePortChannelImpl::postMessage(
+ const WebString& message,
+ WebMessagePortChannel* channel) {
+ if (MessageLoop::current() != ChildThread::current()->message_loop()) {
+ ChildThread::current()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &WebMessagePortChannelImpl::postMessage,
+ message, channel));
+ return;
+ }
+
+ WebMessagePortChannelImpl* webchannel =
+ static_cast<WebMessagePortChannelImpl*>(channel);
+
+ int message_port_id = MSG_ROUTING_NONE;
+ if (webchannel) {
+ message_port_id = webchannel->message_port_id();
+ webchannel->QueueMessages();
+ DCHECK(message_port_id != MSG_ROUTING_NONE);
+ }
+
+ IPC::Message* msg = new WorkerProcessHostMsg_PostMessage(
+ message_port_id_, message, message_port_id);
+
+ Send(msg);
+}
+
+bool WebMessagePortChannelImpl::tryGetMessage(
+ WebString* message,
+ WebMessagePortChannel** channel) {
+ AutoLock auto_lock(lock_);
+ if (message_queue_.empty())
+ return false;
+
+ *message = message_queue_.front().message;
+ *channel = message_queue_.front().port.release();
+ message_queue_.pop();
+ return true;
+}
+
+void WebMessagePortChannelImpl::Init() {
+ if (MessageLoop::current() != ChildThread::current()->message_loop()) {
+ ChildThread::current()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &WebMessagePortChannelImpl::Init));
+ return;
+ }
+
+ if (route_id_ == MSG_ROUTING_NONE) {
+ DCHECK(message_port_id_ == MSG_ROUTING_NONE);
+ Send(new WorkerProcessHostMsg_CreateMessagePort(
+ &route_id_, &message_port_id_));
+ }
+
+ ChildThread::current()->AddRoute(route_id_, this);
+}
+
+void WebMessagePortChannelImpl::Entangle(
+ scoped_refptr<WebMessagePortChannelImpl> channel) {
+ if (MessageLoop::current() != ChildThread::current()->message_loop()) {
+ ChildThread::current()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &WebMessagePortChannelImpl::Entangle, channel));
+ return;
+ }
+
+ Send(new WorkerProcessHostMsg_Entangle(
+ message_port_id_, channel->message_port_id()));
+}
+
+void WebMessagePortChannelImpl::QueueMessages() {
+ // This message port is being sent elsewhere (perhaps to another process).
+ // The new endpoint needs to recieve the queued messages, including ones that
+ // could still be in-flight. So we tell the browser to queue messages, and it
+ // sends us an ack, whose receipt we know means that no more messages are
+ // in-flight. We then send the queued messages to the browser, which prepends
+ // them to the ones it queued and it sends them to the new endpoint.
+ Send(new WorkerProcessHostMsg_QueueMessages(message_port_id_));
+
+ // The process could potentially go away while we're still waiting for
+ // in-flight messages. Ensure it stays alive.
+ ChildProcess::current()->AddRefProcess();
+}
+
+void WebMessagePortChannelImpl::Send(IPC::Message* message) {
+ if (MessageLoop::current() != ChildThread::current()->message_loop()) {
+ DCHECK(!message->is_sync());
+ ChildThread::current()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &WebMessagePortChannelImpl::Send, message));
+ return;
+ }
+
+ ChildThread::current()->Send(message);
+}
+
+void WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) {
+ IPC_BEGIN_MESSAGE_MAP(WebMessagePortChannelImpl, message)
+ IPC_MESSAGE_HANDLER(WorkerProcessMsg_Message, OnMessage)
+ IPC_MESSAGE_HANDLER(WorkerProcessMsg_MessagesQueued, OnMessagedQueued)
+ IPC_END_MESSAGE_MAP()
+}
+
+void WebMessagePortChannelImpl::OnMessage(const string16& message,
+ int sent_message_port_id,
+ int new_routing_id) {
+ AutoLock auto_lock(lock_);
+ Message msg;
+ msg.message = message;
+ msg.port = NULL;
+ if (sent_message_port_id != MSG_ROUTING_NONE) {
+ msg.port = new WebMessagePortChannelImpl(
+ new_routing_id, sent_message_port_id);
+ }
+
+ bool was_empty = message_queue_.empty();
+ message_queue_.push(msg);
+ if (client_ && was_empty)
+ client_->messageAvailable();
+}
+
+void WebMessagePortChannelImpl::OnMessagedQueued() {
+ std::vector<std::pair<string16, int> > queued_messages;
+
+ {
+ AutoLock auto_lock(lock_);
+ queued_messages.reserve(message_queue_.size());
+ while (!message_queue_.empty()) {
+ string16 message = message_queue_.front().message;
+ int port = MSG_ROUTING_NONE;
+ if (message_queue_.front().port)
+ port = message_queue_.front().port->message_port_id();
+
+ queued_messages.push_back(std::make_pair(message, port));
+ message_queue_.pop();
+ }
+ }
+
+ Send(new WorkerProcessHostMsg_SendQueuedMessages(
+ message_port_id_, queued_messages));
+
+ message_port_id_ = MSG_ROUTING_NONE;
+
+ Release();
+ ChildProcess::current()->ReleaseProcess();
+}
diff --git a/chrome/common/webmessageportchannel_impl.h b/chrome/common/webmessageportchannel_impl.h
new file mode 100644
index 0000000..ee26e66
--- /dev/null
+++ b/chrome/common/webmessageportchannel_impl.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_
+#define CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_
+
+#include <queue>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "base/string16.h"
+#include "base/ref_counted.h"
+#include "ipc/ipc_channel.h"
+#include "webkit/api/public/WebMessagePortChannel.h"
+
+// This is thread safe.
+class WebMessagePortChannelImpl
+ : public WebKit::WebMessagePortChannel,
+ public IPC::Channel::Listener,
+ public base::RefCountedThreadSafe<WebMessagePortChannelImpl> {
+ public:
+ WebMessagePortChannelImpl();
+ WebMessagePortChannelImpl(int route_id, int message_port_id);
+
+ // Queues received and incoming messages until there are no more in-flight
+ // messages, then sends all of them to the browser process.
+ void QueueMessages();
+ int message_port_id() const { return message_port_id_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<WebMessagePortChannelImpl>;
+ ~WebMessagePortChannelImpl();
+
+ // WebMessagePortChannel implementation.
+ virtual void setClient(WebKit::WebMessagePortChannelClient* client);
+ virtual void destroy();
+ virtual void entangle(WebKit::WebMessagePortChannel* channel);
+ virtual void postMessage(const WebKit::WebString& message,
+ WebKit::WebMessagePortChannel* channel);
+ virtual bool tryGetMessage(WebKit::WebString* message,
+ WebKit::WebMessagePortChannel** channel);
+
+ void Init();
+ void Entangle(scoped_refptr<WebMessagePortChannelImpl> channel);
+ void Send(IPC::Message* message);
+
+ // IPC::Channel::Listener implementation.
+ virtual void OnMessageReceived(const IPC::Message& message);
+
+ void OnMessage(const string16& message,
+ int sent_message_port_id,
+ int new_routing_id);
+ void OnMessagedQueued();
+
+ struct Message {
+ string16 message;
+ scoped_refptr<WebMessagePortChannelImpl> port;
+ };
+
+ typedef std::queue<Message> MessageQueue;
+ MessageQueue message_queue_;
+
+ WebKit::WebMessagePortChannelClient* client_;
+ Lock lock_; // Locks access to above.
+
+ int route_id_; // The routing id for this object.
+ int message_port_id_; // A globally unique identifier for this message port.
+
+ DISALLOW_COPY_AND_ASSIGN(WebMessagePortChannelImpl);
+};
+
+#endif // CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_
diff --git a/chrome/common/worker_messages.h b/chrome/common/worker_messages.h
index 80004e5..b929d2c 100644
--- a/chrome/common/worker_messages.h
+++ b/chrome/common/worker_messages.h
@@ -14,6 +14,8 @@
#include "chrome/common/common_param_traits.h"
#include "ipc/ipc_message_utils.h"
+typedef std::pair<string16, int> QueuedMessage;
+
// Parameters structure for WorkerHostMsg_PostConsoleMessageToWorkerObject,
// which has too many data parameters to be reasonably put in a predefined
// IPC message. The data members directly correspond to parameters of
diff --git a/chrome/common/worker_messages_internal.h b/chrome/common/worker_messages_internal.h
index 9059719..eb536e8 100644
--- a/chrome/common/worker_messages_internal.h
+++ b/chrome/common/worker_messages_internal.h
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <utility>
#include "base/string16.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message_macros.h"
@@ -14,6 +15,18 @@ IPC_BEGIN_MESSAGES(WorkerProcess)
IPC_MESSAGE_CONTROL2(WorkerProcessMsg_CreateWorker,
GURL /* url */,
int /* route_id */)
+
+ // Note: these Message Port related messages can also be sent to the
+ // renderer process. Putting them here since we don't have a shared place
+ // like common_messages_internal.h
+ IPC_MESSAGE_ROUTED3(WorkerProcessMsg_Message,
+ string16 /* message */,
+ int /* sent_message_port_id */,
+ int /* new_routing_id */)
+
+ // Tells the Message Port Channel object that there are no more in-flight
+ // messages arriving.
+ IPC_MESSAGE_ROUTED0(WorkerProcessMsg_MessagesQueued)
IPC_END_MESSAGES(WorkerProcess)
@@ -21,9 +34,48 @@ IPC_END_MESSAGES(WorkerProcess)
// WorkerProcessHost messages
// These are messages sent from the worker process to the browser process.
-// No messages being sent in this direction for now.
-//IPC_BEGIN_MESSAGES(WorkerProcessHost)
-//IPC_END_MESSAGES(WorkerProcessHost)
+IPC_BEGIN_MESSAGES(WorkerProcessHost)
+ // Note: these Message Port related messages can also be sent out from the
+ // renderer process. Putting them here since we don't have a shared place
+ // like common_messages_internal.h
+
+ // Creates a new Message Port Channel object. The first paramaeter is the
+ // message port channel's routing id in this process. The second parameter
+ // is the process-wide-unique identifier for that port.
+ IPC_SYNC_MESSAGE_CONTROL0_2(WorkerProcessHostMsg_CreateMessagePort,
+ int /* route_id */,
+ int /* message_port_id */)
+
+ // Sent when a Message Port Channel object is destroyed.
+ IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_DestroyMessagePort,
+ int /* message_port_id */)
+
+ // Sends a message to a message port. Optionally sends a message port as
+ // as well if sent_message_port_id != MSG_ROUTING_NONE.
+ IPC_MESSAGE_CONTROL3(WorkerProcessHostMsg_PostMessage,
+ int /* sender_message_port_id */,
+ string16 /* message */,
+ int /* sent_message_port_id */)
+
+ // Causes messages sent to the remote port to be delivered to this local port.
+ IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_Entangle,
+ int /* local_message_port_id */,
+ int /* remote_message_port_id */)
+
+ // Causes the browser to queue messages sent to this port until the the port
+ // has made sure that all in-flight messages were routed to the new
+ // destination.
+ IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_QueueMessages,
+ int /* message_port_id */)
+
+ // Sends the browser all the queued messages that arrived at this message port
+ // after it was sent in a postMessage call.
+ // NOTE: MSVS can't compile the macro if std::vector<std::pair<string16, int> >
+ // is used, so we typedef it in worker_messages.h.
+ IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_SendQueuedMessages,
+ int /* message_port_id */,
+ std::vector<QueuedMessage> /* queued_messages */)
+IPC_END_MESSAGES(WorkerProcessHost)
//-----------------------------------------------------------------------------
// Worker messages
diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc
index c086d0d..e19487b 100644
--- a/chrome/renderer/renderer_webkitclient_impl.cc
+++ b/chrome/renderer/renderer_webkitclient_impl.cc
@@ -10,6 +10,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/db_message_filter.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/webmessageportchannel_impl.h"
#include "chrome/plugin/npobject_util.h"
#include "chrome/renderer/net/render_dns_master.h"
#include "chrome/renderer/render_thread.h"
@@ -70,6 +71,11 @@ bool RendererWebKitClientImpl::isLinkVisited(unsigned long long link_hash) {
return RenderThread::current()->visited_link_slave()->IsVisited(link_hash);
}
+WebKit::WebMessagePortChannel*
+RendererWebKitClientImpl::createMessagePortChannel() {
+ return new WebMessagePortChannelImpl();
+}
+
void RendererWebKitClientImpl::setCookies(const WebURL& url,
const WebURL& first_party_for_cookies,
const WebString& value) {
diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h
index 1f1880d..3d5828c 100644
--- a/chrome/renderer/renderer_webkitclient_impl.h
+++ b/chrome/renderer/renderer_webkitclient_impl.h
@@ -29,6 +29,7 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl {
virtual unsigned long long visitedLinkHash(
const char* canonicalURL, size_t length);
virtual bool isLinkVisited(unsigned long long linkHash);
+ virtual WebKit::WebMessagePortChannel* createMessagePortChannel();
virtual void setCookies(const WebKit::WebURL& url,
const WebKit::WebURL& first_party_for_cookies,
const WebKit::WebString&);
diff --git a/chrome/worker/worker_uitest.cc b/chrome/worker/worker_uitest.cc
index e493203..62c618c 100644
--- a/chrome/worker/worker_uitest.cc
+++ b/chrome/worker/worker_uitest.cc
@@ -374,6 +374,35 @@ TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
StopHttpServer();
}
+TEST_F(WorkerTest, MessagePorts) {
+ static const char* kLayoutTestFiles[] = {
+ "message-channel-gc.html",
+ "message-channel-gc-2.html",
+ "message-channel-gc-3.html",
+ "message-channel-gc-4.html",
+ "message-port.html",
+ "message-port-clone.html",
+ "message-port-constructor-for-deleted-document.html",
+ "message-port-deleted-document.html",
+ "message-port-deleted-frame.html",
+ "message-port-inactive-document.html",
+ "message-port-no-wrapper.html",
+ // Only works with run-webkit-tests --leaks.
+ //"message-channel-listener-circular-ownership.html",
+ };
+
+ FilePath fast_test_dir;
+ fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
+ fast_test_dir = fast_test_dir.AppendASCII("fast");
+
+ FilePath worker_test_dir;
+ worker_test_dir = worker_test_dir.AppendASCII("events");
+ InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);
+
+ for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
+ RunLayoutTest(kLayoutTestFiles[i], false);
+}
+
TEST_F(WorkerTest, LimitPerPage) {
int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
GURL url = GetTestUrl(L"workers", L"many_workers.html");
diff --git a/chrome/worker/worker_webkitclient_impl.cc b/chrome/worker/worker_webkitclient_impl.cc
index 21ca49a..4923542 100644
--- a/chrome/worker/worker_webkitclient_impl.cc
+++ b/chrome/worker/worker_webkitclient_impl.cc
@@ -5,6 +5,7 @@
#include "chrome/worker/worker_webkitclient_impl.h"
#include "base/logging.h"
+#include "chrome/common/webmessageportchannel_impl.h"
#include "chrome/worker/worker_thread.h"
#include "webkit/api/public/WebString.h"
#include "webkit/api/public/WebURL.h"
@@ -36,6 +37,11 @@ bool WorkerWebKitClientImpl::isLinkVisited(unsigned long long link_hash) {
return false;
}
+WebKit::WebMessagePortChannel*
+WorkerWebKitClientImpl::createMessagePortChannel() {
+ return new WebMessagePortChannelImpl();
+}
+
void WorkerWebKitClientImpl::setCookies(const WebKit::WebURL& url,
const WebKit::WebURL& policy_url,
const WebKit::WebString& value) {
diff --git a/chrome/worker/worker_webkitclient_impl.h b/chrome/worker/worker_webkitclient_impl.h
index ecd3220..69a28e4 100644
--- a/chrome/worker/worker_webkitclient_impl.h
+++ b/chrome/worker/worker_webkitclient_impl.h
@@ -16,6 +16,7 @@ class WorkerWebKitClientImpl : public webkit_glue::WebKitClientImpl {
virtual unsigned long long visitedLinkHash(const char* canonicalURL,
size_t length);
virtual bool isLinkVisited(unsigned long long linkHash);
+ virtual WebKit::WebMessagePortChannel* createMessagePortChannel();
virtual void setCookies(const WebKit::WebURL& url,
const WebKit::WebURL& policy_url,
const WebKit::WebString& value);