diff options
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/notification_type.h | 4 | ||||
-rw-r--r-- | chrome/common/webmessageportchannel_impl.cc | 204 | ||||
-rw-r--r-- | chrome/common/webmessageportchannel_impl.h | 73 | ||||
-rw-r--r-- | chrome/common/worker_messages.h | 2 | ||||
-rw-r--r-- | chrome/common/worker_messages_internal.h | 58 |
5 files changed, 338 insertions, 3 deletions
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 |