Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_MessagePort_h
8
#define mozilla_dom_MessagePort_h
9
10
#include "mozilla/Attributes.h"
11
#include "mozilla/DOMEventTargetHelper.h"
12
#include "mozilla/dom/DOMTypes.h"
13
#include "mozilla/UniquePtr.h"
14
#include "nsTArray.h"
15
16
#ifdef XP_WIN
17
# undef PostMessage
18
#endif
19
20
class nsIGlobalObject;
21
22
namespace mozilla {
23
namespace dom {
24
25
class MessageData;
26
class MessagePortChild;
27
struct PostMessageOptions;
28
class PostMessageRunnable;
29
class SharedMessageBody;
30
class RefMessageBodyService;
31
class StrongWorkerRef;
32
33
// A class to hold a MessagePortIdentifier from
34
// MessagePort::CloneAndDistentangle() and close if neither passed to
35
// MessagePort::Create() nor release()ed to send via IPC.
36
// When the `neutered` field of the MessagePortIdentifier is false, a close is
37
// required.
38
// This does not derive from MessagePortIdentifier because
39
// MessagePortIdentifier is final and because use of UniqueMessagePortId as a
40
// MessagePortIdentifier is intentionally prevented without release of
41
// ownership.
42
class UniqueMessagePortId final {
43
public:
44
UniqueMessagePortId() { mIdentifier.neutered() = true; }
45
explicit UniqueMessagePortId(const MessagePortIdentifier& aIdentifier)
46
: mIdentifier(aIdentifier) {}
47
UniqueMessagePortId(UniqueMessagePortId&& aOther) noexcept
48
: mIdentifier(aOther.mIdentifier) {
49
aOther.mIdentifier.neutered() = true;
50
}
51
~UniqueMessagePortId() { ForceClose(); };
52
void ForceClose();
53
54
MOZ_MUST_USE MessagePortIdentifier release() {
55
MessagePortIdentifier id = mIdentifier;
56
mIdentifier.neutered() = true;
57
return id;
58
}
59
// const member accessors are not required because a const
60
// UniqueMessagePortId is not useful.
61
nsID& uuid() { return mIdentifier.uuid(); }
62
nsID& destinationUuid() { return mIdentifier.destinationUuid(); }
63
uint32_t& sequenceId() { return mIdentifier.sequenceId(); }
64
bool& neutered() { return mIdentifier.neutered(); }
65
66
UniqueMessagePortId(const UniqueMessagePortId& aOther) = delete;
67
void operator=(const UniqueMessagePortId& aOther) = delete;
68
69
private:
70
MessagePortIdentifier mIdentifier;
71
};
72
73
class MessagePort final : public DOMEventTargetHelper {
74
friend class PostMessageRunnable;
75
76
public:
77
NS_DECL_ISUPPORTS_INHERITED
78
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper)
79
80
static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal,
81
const nsID& aUUID,
82
const nsID& aDestinationUUID,
83
ErrorResult& aRv);
84
85
static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal,
86
UniqueMessagePortId& aIdentifier,
87
ErrorResult& aRv);
88
89
// For IPC.
90
static void ForceClose(const MessagePortIdentifier& aIdentifier);
91
92
virtual JSObject* WrapObject(JSContext* aCx,
93
JS::Handle<JSObject*> aGivenProto) override;
94
95
void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
96
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
97
98
void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
99
const PostMessageOptions& aOptions, ErrorResult& aRv);
100
101
void Start();
102
103
void Close();
104
105
EventHandlerNonNull* GetOnmessage();
106
107
void SetOnmessage(EventHandlerNonNull* aCallback);
108
109
IMPL_EVENT_HANDLER(messageerror)
110
111
// Non WebIDL methods
112
113
void UnshippedEntangle(MessagePort* aEntangledPort);
114
115
bool CanBeCloned() const { return !mHasBeenTransferredOrClosed; }
116
117
void CloneAndDisentangle(UniqueMessagePortId& aIdentifier);
118
119
void CloseForced();
120
121
// These methods are useful for MessagePortChild
122
123
void Entangled(nsTArray<MessageData>& aMessages);
124
void MessagesReceived(nsTArray<MessageData>& aMessages);
125
void StopSendingDataConfirmed();
126
void Closed();
127
128
private:
129
enum State {
130
// When a port is created by a MessageChannel it is entangled with the
131
// other. They both run on the same thread, same event loop and the
132
// messages are added to the queues without using PBackground actors.
133
// When one of the port is shipped, the state is changed to
134
// StateEntangling.
135
eStateUnshippedEntangled,
136
137
// If the port is closed or cloned when we are in this state, we go in one
138
// of the following 2 steps. EntanglingForClose or ForDisentangle.
139
eStateEntangling,
140
141
// We are not fully entangled yet but are already disentangled.
142
eStateEntanglingForDisentangle,
143
144
// We are not fully entangled yet but are already closed.
145
eStateEntanglingForClose,
146
147
// When entangled() is received we send all the messages in the
148
// mMessagesForTheOtherPort to the actor and we change the state to
149
// StateEntangled. At this point the port is entangled with the other. We
150
// send and receive messages.
151
// If the port queue is not enabled, the received messages are stored in
152
// the mMessages.
153
eStateEntangled,
154
155
// When the port is cloned or disentangled we want to stop receiving
156
// messages. We call 'SendStopSendingData' to the actor and we wait for an
157
// answer. All the messages received between now and the
158
// 'StopSendingDataComfirmed are queued in the mMessages but not
159
// dispatched.
160
eStateDisentangling,
161
162
// When 'StopSendingDataConfirmed' is received, we can disentangle the port
163
// calling SendDisentangle in the actor because we are 100% sure that we
164
// don't receive any other message, so nothing will be lost.
165
// Disentangling the port we send all the messages from the mMessages
166
// though the actor.
167
eStateDisentangled,
168
169
// We are here if Close() has been called. We are disentangled but we can
170
// still send pending messages.
171
eStateDisentangledForClose
172
};
173
174
explicit MessagePort(nsIGlobalObject* aGlobal, State aState);
175
~MessagePort();
176
177
void DisconnectFromOwner() override;
178
179
void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
180
uint32_t aSequenceID, bool aNeutered, ErrorResult& aRv);
181
182
bool ConnectToPBackground();
183
184
// Dispatch events from the Message Queue using a nsRunnable.
185
void Dispatch();
186
187
void DispatchError();
188
189
void StartDisentangling();
190
void Disentangle();
191
192
void RemoveDocFromBFCache();
193
194
void CloseInternal(bool aSoftly);
195
196
// This method is meant to keep alive the MessagePort when this object is
197
// creating the actor and until the actor is entangled.
198
// We release the object when the port is closed or disentangled.
199
void UpdateMustKeepAlive();
200
201
bool IsCertainlyAliveForCC() const override { return mIsKeptAlive; }
202
203
RefPtr<StrongWorkerRef> mWorkerRef;
204
205
RefPtr<PostMessageRunnable> mPostMessageRunnable;
206
207
RefPtr<MessagePortChild> mActor;
208
209
RefPtr<MessagePort> mUnshippedEntangledPort;
210
211
RefPtr<RefMessageBodyService> mRefMessageBodyService;
212
213
nsTArray<RefPtr<SharedMessageBody>> mMessages;
214
nsTArray<RefPtr<SharedMessageBody>> mMessagesForTheOtherPort;
215
216
UniquePtr<MessagePortIdentifier> mIdentifier;
217
218
State mState;
219
220
bool mMessageQueueEnabled;
221
222
bool mIsKeptAlive;
223
224
// mHasBeenTransferredOrClosed is used to know if this port has been manually
225
// closed or transferred via postMessage. Note that if the entangled port is
226
// closed, this port is closed as well (see mState) but, just because close()
227
// has not been called directly, by spec, this port can still be transferred.
228
bool mHasBeenTransferredOrClosed;
229
};
230
231
} // namespace dom
232
} // namespace mozilla
233
234
#endif // mozilla_dom_MessagePort_h