1/* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "PlatformMessagePortChannel.h" 33 34#include "MessagePort.h" 35#include "ScriptExecutionContext.h" 36 37namespace WebCore { 38 39// MessagePortChannel implementations - just delegate to the PlatformMessagePortChannel. 40void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2) 41{ 42 PlatformMessagePortChannel::createChannel(port1, port2); 43} 44 45PassOwnPtr<MessagePortChannel> MessagePortChannel::create(PassRefPtr<PlatformMessagePortChannel> channel) 46{ 47 return new MessagePortChannel(channel); 48} 49 50MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel) 51 : m_channel(channel) 52{ 53} 54 55MessagePortChannel::~MessagePortChannel() 56{ 57 // Make sure we close our platform channel when the base is freed, to keep the channel objects from leaking. 58 m_channel->close(); 59} 60 61bool MessagePortChannel::entangleIfOpen(MessagePort* port) 62{ 63 return m_channel->entangleIfOpen(port); 64} 65 66void MessagePortChannel::disentangle() 67{ 68 m_channel->disentangle(); 69} 70 71void MessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message) 72{ 73 m_channel->postMessageToRemote(message); 74} 75 76bool MessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result) 77{ 78 return m_channel->tryGetMessageFromRemote(result); 79} 80 81void MessagePortChannel::close() 82{ 83 m_channel->close(); 84} 85 86bool MessagePortChannel::isConnectedTo(MessagePort* port) 87{ 88 return m_channel->isConnectedTo(port); 89} 90 91bool MessagePortChannel::hasPendingActivity() 92{ 93 return m_channel->hasPendingActivity(); 94} 95 96MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context) 97{ 98 return m_channel->locallyEntangledPort(context); 99} 100 101PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 102{ 103 return adoptRef(new PlatformMessagePortChannel(incoming, outgoing)); 104} 105 106PlatformMessagePortChannel::PlatformMessagePortChannel(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 107 : m_entangledChannel(0) 108 , m_incomingQueue(incoming) 109 , m_outgoingQueue(outgoing) 110 , m_remotePort(0) 111{ 112} 113 114PlatformMessagePortChannel::~PlatformMessagePortChannel() 115{ 116} 117 118void PlatformMessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2) 119{ 120 // Create incoming/outgoing queues. 121 RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue1 = PlatformMessagePortChannel::MessagePortQueue::create(); 122 RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue2 = PlatformMessagePortChannel::MessagePortQueue::create(); 123 124 // Create proxies for each endpoint. 125 RefPtr<PlatformMessagePortChannel> channel1 = PlatformMessagePortChannel::create(queue1, queue2); 126 RefPtr<PlatformMessagePortChannel> channel2 = PlatformMessagePortChannel::create(queue2, queue1); 127 128 // Entangle the two endpoints. 129 channel1->setEntangledChannel(channel2); 130 channel2->setEntangledChannel(channel1); 131 132 // Now entangle the proxies with the appropriate local ports. 133 port1->entangle(MessagePortChannel::create(channel2)); 134 port2->entangle(MessagePortChannel::create(channel1)); 135} 136 137bool PlatformMessagePortChannel::entangleIfOpen(MessagePort* port) 138{ 139 // We can't call member functions on our remote pair while holding our mutex or we'll deadlock, but we need to guard against the remote port getting closed/freed, so create a standalone reference. 140 RefPtr<PlatformMessagePortChannel> remote = entangledChannel(); 141 if (!remote) 142 return false; 143 remote->setRemotePort(port); 144 return true; 145} 146 147void PlatformMessagePortChannel::disentangle() 148{ 149 RefPtr<PlatformMessagePortChannel> remote = entangledChannel(); 150 if (remote) 151 remote->setRemotePort(0); 152} 153 154void PlatformMessagePortChannel::setRemotePort(MessagePort* port) 155{ 156 MutexLocker lock(m_mutex); 157 // Should never set port if it is already set. 158 ASSERT(!port || !m_remotePort); 159 m_remotePort = port; 160} 161 162MessagePort* PlatformMessagePortChannel::remotePort() 163{ 164 MutexLocker lock(m_mutex); 165 return m_remotePort; 166} 167 168PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::entangledChannel() 169{ 170 MutexLocker lock(m_mutex); 171 return m_entangledChannel; 172} 173 174void PlatformMessagePortChannel::setEntangledChannel(PassRefPtr<PlatformMessagePortChannel> remote) 175{ 176 MutexLocker lock(m_mutex); 177 // Should only be set as part of initial creation/entanglement. 178 if (remote) 179 ASSERT(!m_entangledChannel.get()); 180 m_entangledChannel = remote; 181} 182 183void PlatformMessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message) 184{ 185 MutexLocker lock(m_mutex); 186 if (!m_outgoingQueue) 187 return; 188 bool wasEmpty = m_outgoingQueue->appendAndCheckEmpty(message); 189 if (wasEmpty && m_remotePort) 190 m_remotePort->messageAvailable(); 191} 192 193bool PlatformMessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result) 194{ 195 MutexLocker lock(m_mutex); 196 result = m_incomingQueue->tryGetMessage(); 197 return result; 198} 199 200bool PlatformMessagePortChannel::isConnectedTo(MessagePort* port) 201{ 202 MutexLocker lock(m_mutex); 203 return m_remotePort == port; 204} 205 206// Closes the port so no further messages can be sent from either end. 207void PlatformMessagePortChannel::close() 208{ 209 RefPtr<PlatformMessagePortChannel> remote = entangledChannel(); 210 if (!remote) 211 return; 212 closeInternal(); 213 remote->closeInternal(); 214} 215 216void PlatformMessagePortChannel::closeInternal() 217{ 218 MutexLocker lock(m_mutex); 219 // Disentangle ourselves from the other end. We still maintain a reference to our incoming queue, since previously-existing messages should still be delivered. 220 m_remotePort = 0; 221 m_entangledChannel = 0; 222 m_outgoingQueue = 0; 223} 224 225bool PlatformMessagePortChannel::hasPendingActivity() 226{ 227 MutexLocker lock(m_mutex); 228 return !m_incomingQueue->isEmpty(); 229} 230 231MessagePort* PlatformMessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context) 232{ 233 MutexLocker lock(m_mutex); 234 // See if both contexts are run by the same thread (are the same context, or are both documents). 235 if (m_remotePort) { 236 // The remote port's ScriptExecutionContext is guaranteed not to change here - MessagePort::contextDestroyed() will close the port before the context goes away, and close() will block because we are holding the mutex. 237 ScriptExecutionContext* remoteContext = m_remotePort->scriptExecutionContext(); 238 if (remoteContext == context || (remoteContext && remoteContext->isDocument() && context->isDocument())) 239 return m_remotePort; 240 } 241 return 0; 242} 243 244} // namespace WebCore 245