902da183400aa9c266b0e29848ca35605248fa71
[WebKit-https.git] / Source / WebCore / dom / default / PlatformMessagePortChannel.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  * Copyright (C) 2013 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "PlatformMessagePortChannel.h"
34
35 #include "MessagePort.h"
36 #include "ScriptExecutionContext.h"
37
38 namespace WebCore {
39
40 std::unique_ptr<PlatformMessagePortChannel::EventData> PlatformMessagePortChannel::EventData::create(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
41 {
42     return std::unique_ptr<EventData>(new EventData(message, channels));
43 }
44
45 PlatformMessagePortChannel::EventData::EventData(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
46     : m_message(message)
47     , m_channels(channels)
48 {
49 }
50
51 void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2)
52 {
53     RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue1 = PlatformMessagePortChannel::MessagePortQueue::create();
54     RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue2 = PlatformMessagePortChannel::MessagePortQueue::create();
55
56     OwnPtr<MessagePortChannel> channel1 = adoptPtr(new MessagePortChannel(PlatformMessagePortChannel::create(queue1, queue2)));
57     OwnPtr<MessagePortChannel> channel2 = adoptPtr(new MessagePortChannel(PlatformMessagePortChannel::create(queue2, queue1)));
58
59     channel1->m_channel->m_entangledChannel = channel2->m_channel;
60     channel2->m_channel->m_entangledChannel = channel1->m_channel;
61
62     port1->entangle(channel2.release());
63     port2->entangle(channel1.release());
64 }
65
66 MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel)
67     : m_channel(channel)
68 {
69 }
70
71 MessagePortChannel::~MessagePortChannel()
72 {
73     close();
74 }
75
76 bool MessagePortChannel::entangleIfOpen(MessagePort* port)
77 {
78     // We can't call member functions on our remote pair while holding our mutex or we'll deadlock,
79     // but we need to guard against the remote port getting closed/freed, so create a standalone reference.
80     RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel();
81     if (!remote)
82         return false;
83     remote->setRemotePort(port);
84     return true;
85 }
86
87 void MessagePortChannel::disentangle()
88 {
89     RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel();
90     if (remote)
91         remote->setRemotePort(0);
92 }
93
94 void MessagePortChannel::postMessageToRemote(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
95 {
96     MutexLocker lock(m_channel->m_mutex);
97     if (!m_channel->m_outgoingQueue)
98         return;
99     bool wasEmpty = m_channel->m_outgoingQueue->appendAndCheckEmpty(PlatformMessagePortChannel::EventData::create(message, channels));
100     if (wasEmpty && m_channel->m_remotePort)
101         m_channel->m_remotePort->messageAvailable();
102 }
103
104 bool MessagePortChannel::tryGetMessageFromRemote(RefPtr<SerializedScriptValue>& message, OwnPtr<MessagePortChannelArray>& channels)
105 {
106     MutexLocker lock(m_channel->m_mutex);
107     auto result = m_channel->m_incomingQueue->tryGetMessage();
108     if (!result)
109         return false;
110
111     message = result->message();
112     channels = result->channels();
113
114     return true;
115 }
116
117 void MessagePortChannel::close()
118 {
119     RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel();
120     if (!remote)
121         return;
122     m_channel->closeInternal();
123     remote->closeInternal();
124 }
125
126 bool MessagePortChannel::isConnectedTo(MessagePort* port)
127 {
128     // FIXME: What guarantees that the result remains the same after we release the lock?
129     MutexLocker lock(m_channel->m_mutex);
130     return m_channel->m_remotePort == port;
131 }
132
133 bool MessagePortChannel::hasPendingActivity()
134 {
135     // FIXME: What guarantees that the result remains the same after we release the lock?
136     MutexLocker lock(m_channel->m_mutex);
137     return !m_channel->m_incomingQueue->isEmpty();
138 }
139
140 MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context)
141 {
142     MutexLocker lock(m_channel->m_mutex);
143     // See if both contexts are run by the same thread (are the same context, or are both documents).
144     if (m_channel->m_remotePort) {
145         // The remote port's ScriptExecutionContext is guaranteed not to change here - MessagePort::contextDestroyed()
146         // will close the port before the context goes away, and close() will block because we are holding the mutex.
147         ScriptExecutionContext* remoteContext = m_channel->m_remotePort->scriptExecutionContext();
148         if (remoteContext == context || (remoteContext && remoteContext->isDocument() && context->isDocument()))
149             return m_channel->m_remotePort;
150     }
151     return 0;
152 }
153
154 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing)
155 {
156     return adoptRef(new PlatformMessagePortChannel(incoming, outgoing));
157 }
158
159 PlatformMessagePortChannel::PlatformMessagePortChannel(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing)
160     : m_incomingQueue(incoming)
161     , m_outgoingQueue(outgoing)
162     , m_remotePort(0)
163 {
164 }
165
166 PlatformMessagePortChannel::~PlatformMessagePortChannel()
167 {
168 }
169
170 void PlatformMessagePortChannel::setRemotePort(MessagePort* port)
171 {
172     MutexLocker lock(m_mutex);
173     // Should never set port if it is already set.
174     ASSERT(!port || !m_remotePort);
175     m_remotePort = port;
176 }
177
178 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::entangledChannel()
179 {
180     // FIXME: What guarantees that the result remains the same after we release the lock?
181     // This lock only guarantees that the returned pointer will not be pointing to released memory,
182     // but not that it will still be pointing to this object's entangled port channel.
183     MutexLocker lock(m_mutex);
184     return m_entangledChannel;
185 }
186
187 void PlatformMessagePortChannel::closeInternal()
188 {
189     MutexLocker lock(m_mutex);
190     // Disentangle ourselves from the other end. We still maintain a reference to our incoming queue, since previously-existing messages should still be delivered.
191     m_remotePort = 0;
192     m_entangledChannel = 0;
193     m_outgoingQueue = 0;
194 }
195
196 } // namespace WebCore