dfa5320be246e389495dc6795e00a7d22330bc2c
[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 PlatformMessagePortChannel::EventData::EventData(PassRefPtr<SerializedScriptValue> message, std::unique_ptr<MessagePortChannelArray> channels)
41     : m_message(message)
42     , m_channels(WTF::move(channels))
43 {
44 }
45
46 void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2)
47 {
48     RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue1 = PlatformMessagePortChannel::MessagePortQueue::create();
49     RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue2 = PlatformMessagePortChannel::MessagePortQueue::create();
50
51     auto channel1 = std::make_unique<MessagePortChannel>(PlatformMessagePortChannel::create(queue1, queue2));
52     auto channel2 = std::make_unique<MessagePortChannel>(PlatformMessagePortChannel::create(queue2, queue1));
53
54     channel1->m_channel->m_entangledChannel = channel2->m_channel;
55     channel2->m_channel->m_entangledChannel = channel1->m_channel;
56
57     port1->entangle(WTF::move(channel2));
58     port2->entangle(WTF::move(channel1));
59 }
60
61 MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel)
62     : m_channel(channel)
63 {
64 }
65
66 MessagePortChannel::~MessagePortChannel()
67 {
68     close();
69 }
70
71 bool MessagePortChannel::entangleIfOpen(MessagePort* port)
72 {
73     // We can't call member functions on our remote pair while holding our mutex or we'll deadlock,
74     // but we need to guard against the remote port getting closed/freed, so create a standalone reference.
75     RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel();
76     if (!remote)
77         return false;
78     remote->setRemotePort(port);
79     return true;
80 }
81
82 void MessagePortChannel::disentangle()
83 {
84     RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel();
85     if (remote)
86         remote->setRemotePort(0);
87 }
88
89 void MessagePortChannel::postMessageToRemote(PassRefPtr<SerializedScriptValue> message, std::unique_ptr<MessagePortChannelArray> channels)
90 {
91     DeprecatedMutexLocker lock(m_channel->m_mutex);
92     if (!m_channel->m_outgoingQueue)
93         return;
94     bool wasEmpty = m_channel->m_outgoingQueue->appendAndCheckEmpty(std::make_unique<PlatformMessagePortChannel::EventData>(message, WTF::move(channels)));
95     if (wasEmpty && m_channel->m_remotePort)
96         m_channel->m_remotePort->messageAvailable();
97 }
98
99 bool MessagePortChannel::tryGetMessageFromRemote(RefPtr<SerializedScriptValue>& message, std::unique_ptr<MessagePortChannelArray>& channels)
100 {
101     DeprecatedMutexLocker lock(m_channel->m_mutex);
102     auto result = m_channel->m_incomingQueue->tryGetMessage();
103     if (!result)
104         return false;
105
106     message = result->message();
107     channels = result->channels();
108
109     return true;
110 }
111
112 void MessagePortChannel::close()
113 {
114     RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel();
115     if (!remote)
116         return;
117     m_channel->closeInternal();
118     remote->closeInternal();
119 }
120
121 bool MessagePortChannel::isConnectedTo(MessagePort* port)
122 {
123     // FIXME: What guarantees that the result remains the same after we release the lock?
124     DeprecatedMutexLocker lock(m_channel->m_mutex);
125     return m_channel->m_remotePort == port;
126 }
127
128 bool MessagePortChannel::hasPendingActivity()
129 {
130     // FIXME: What guarantees that the result remains the same after we release the lock?
131     DeprecatedMutexLocker lock(m_channel->m_mutex);
132     return !m_channel->m_incomingQueue->isEmpty();
133 }
134
135 MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context)
136 {
137     DeprecatedMutexLocker lock(m_channel->m_mutex);
138     // See if both contexts are run by the same thread (are the same context, or are both documents).
139     if (m_channel->m_remotePort) {
140         // The remote port's ScriptExecutionContext is guaranteed not to change here - MessagePort::contextDestroyed()
141         // will close the port before the context goes away, and close() will block because we are holding the mutex.
142         ScriptExecutionContext* remoteContext = m_channel->m_remotePort->scriptExecutionContext();
143         if (remoteContext == context || (remoteContext && remoteContext->isDocument() && context->isDocument()))
144             return m_channel->m_remotePort;
145     }
146     return 0;
147 }
148
149 Ref<PlatformMessagePortChannel> PlatformMessagePortChannel::create(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing)
150 {
151     return adoptRef(*new PlatformMessagePortChannel(incoming, outgoing));
152 }
153
154 PlatformMessagePortChannel::PlatformMessagePortChannel(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing)
155     : m_incomingQueue(incoming)
156     , m_outgoingQueue(outgoing)
157     , m_remotePort(0)
158 {
159 }
160
161 PlatformMessagePortChannel::~PlatformMessagePortChannel()
162 {
163 }
164
165 void PlatformMessagePortChannel::setRemotePort(MessagePort* port)
166 {
167     DeprecatedMutexLocker lock(m_mutex);
168     // Should never set port if it is already set.
169     ASSERT(!port || !m_remotePort);
170     m_remotePort = port;
171 }
172
173 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::entangledChannel()
174 {
175     // FIXME: What guarantees that the result remains the same after we release the lock?
176     // This lock only guarantees that the returned pointer will not be pointing to released memory,
177     // but not that it will still be pointing to this object's entangled port channel.
178     DeprecatedMutexLocker lock(m_mutex);
179     return m_entangledChannel;
180 }
181
182 void PlatformMessagePortChannel::closeInternal()
183 {
184     DeprecatedMutexLocker lock(m_mutex);
185     // Disentangle ourselves from the other end. We still maintain a reference to our incoming queue, since previously-existing messages should still be delivered.
186     m_remotePort = nullptr;
187     m_entangledChannel = nullptr;
188     m_outgoingQueue = nullptr;
189 }
190
191 } // namespace WebCore