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 37 namespace WebCore { 38 39 // MessagePortChannel implementations - just delegate to the PlatformMessagePortChannel. 40 void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2) 41 { 42 PlatformMessagePortChannel::createChannel(port1, port2); 43 } 44 45 PassOwnPtr<MessagePortChannel> MessagePortChannel::create(PassRefPtr<PlatformMessagePortChannel> channel) 46 { 47 return new MessagePortChannel(channel); 48 } 49 50 MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel) 51 : m_channel(channel) 52 { 53 } 54 55 MessagePortChannel::~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 61 bool MessagePortChannel::entangleIfOpen(MessagePort* port) 62 { 63 return m_channel->entangleIfOpen(port); 64 } 65 66 void MessagePortChannel::disentangle() 67 { 68 m_channel->disentangle(); 69 } 70 71 void MessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message) 72 { 73 m_channel->postMessageToRemote(message); 74 } 75 76 bool MessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result) 77 { 78 return m_channel->tryGetMessageFromRemote(result); 79 } 80 81 void MessagePortChannel::close() 82 { 83 m_channel->close(); 84 } 85 86 bool MessagePortChannel::isConnectedTo(MessagePort* port) 87 { 88 return m_channel->isConnectedTo(port); 89 } 90 91 bool MessagePortChannel::hasPendingActivity() 92 { 93 return m_channel->hasPendingActivity(); 94 } 95 96 MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context) 97 { 98 return m_channel->locallyEntangledPort(context); 99 } 100 101 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 102 { 103 return adoptRef(new PlatformMessagePortChannel(incoming, outgoing)); 104 } 105 106 PlatformMessagePortChannel::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 114 PlatformMessagePortChannel::~PlatformMessagePortChannel() 115 { 116 } 117 118 void 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 137 bool 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 147 void PlatformMessagePortChannel::disentangle() 148 { 149 RefPtr<PlatformMessagePortChannel> remote = entangledChannel(); 150 if (remote) 151 remote->setRemotePort(0); 152 } 153 154 void 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 162 MessagePort* PlatformMessagePortChannel::remotePort() 163 { 164 MutexLocker lock(m_mutex); 165 return m_remotePort; 166 } 167 168 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::entangledChannel() 169 { 170 MutexLocker lock(m_mutex); 171 return m_entangledChannel; 172 } 173 174 void 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 183 void 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 193 bool PlatformMessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result) 194 { 195 MutexLocker lock(m_mutex); 196 result = m_incomingQueue->tryGetMessage(); 197 return result; 198 } 199 200 bool 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. 207 void PlatformMessagePortChannel::close() 208 { 209 RefPtr<PlatformMessagePortChannel> remote = entangledChannel(); 210 if (!remote) 211 return; 212 closeInternal(); 213 remote->closeInternal(); 214 } 215 216 void 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 225 bool PlatformMessagePortChannel::hasPendingActivity() 226 { 227 MutexLocker lock(m_mutex); 228 return !m_incomingQueue->isEmpty(); 229 } 230 231 MessagePort* 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