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 "nsAutoPtr.h" 13 #include "nsIIPCBackgroundChildCreateCallback.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 MessagePortChild; 26 class MessagePortIdentifier; 27 class MessagePortMessage; 28 class PostMessageRunnable; 29 class SharedMessagePortMessage; 30 31 namespace workers { 32 class WorkerHolder; 33 } // namespace workers 34 35 class MessagePort final : public DOMEventTargetHelper 36 , public nsIIPCBackgroundChildCreateCallback 37 , public nsIObserver 38 { 39 friend class PostMessageRunnable; 40 41 public: 42 NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK 43 NS_DECL_NSIOBSERVER 44 NS_DECL_ISUPPORTS_INHERITED 45 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, 46 DOMEventTargetHelper) 47 48 static already_AddRefed<MessagePort> 49 Create(nsIGlobalObject* aGlobal, const nsID& aUUID, 50 const nsID& aDestinationUUID, ErrorResult& aRv); 51 52 static already_AddRefed<MessagePort> 53 Create(nsIGlobalObject* aGlobal, 54 const MessagePortIdentifier& aIdentifier, 55 ErrorResult& aRv); 56 57 // For IPC. 58 static void 59 ForceClose(const MessagePortIdentifier& aIdentifier); 60 61 virtual JSObject* 62 WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; 63 64 void 65 PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, 66 const Optional<Sequence<JS::Value>>& aTransferable, 67 ErrorResult& aRv); 68 69 void Start(); 70 71 void Close(); 72 73 EventHandlerNonNull* GetOnmessage(); 74 75 void SetOnmessage(EventHandlerNonNull* aCallback); 76 77 // Non WebIDL methods 78 79 void UnshippedEntangle(MessagePort* aEntangledPort); 80 81 void CloneAndDisentangle(MessagePortIdentifier& aIdentifier); 82 83 void CloseForced(); 84 85 // These methods are useful for MessagePortChild 86 87 void Entangled(nsTArray<MessagePortMessage>& aMessages); 88 void MessagesReceived(nsTArray<MessagePortMessage>& aMessages); 89 void StopSendingDataConfirmed(); 90 void Closed(); 91 92 private: 93 explicit MessagePort(nsIGlobalObject* aGlobal); 94 ~MessagePort(); 95 96 enum State { 97 // When a port is created by a MessageChannel it is entangled with the 98 // other. They both run on the same thread, same event loop and the 99 // messages are added to the queues without using PBackground actors. 100 // When one of the port is shipped, the state is changed to 101 // StateEntangling. 102 eStateUnshippedEntangled, 103 104 // If the port is closed or cloned when we are in this state, we go in one 105 // of the following 2 steps. EntanglingForClose or ForDisentangle. 106 eStateEntangling, 107 108 // We are not fully entangled yet but are already disentangled. 109 eStateEntanglingForDisentangle, 110 111 // We are not fully entangled yet but are already closed. 112 eStateEntanglingForClose, 113 114 // When entangled() is received we send all the messages in the 115 // mMessagesForTheOtherPort to the actor and we change the state to 116 // StateEntangled. At this point the port is entangled with the other. We 117 // send and receive messages. 118 // If the port queue is not enabled, the received messages are stored in 119 // the mMessages. 120 eStateEntangled, 121 122 // When the port is cloned or disentangled we want to stop receiving 123 // messages. We call 'SendStopSendingData' to the actor and we wait for an 124 // answer. All the messages received between now and the 125 // 'StopSendingDataComfirmed are queued in the mMessages but not 126 // dispatched. 127 eStateDisentangling, 128 129 // When 'StopSendingDataConfirmed' is received, we can disentangle the port 130 // calling SendDisentangle in the actor because we are 100% sure that we 131 // don't receive any other message, so nothing will be lost. 132 // Disentangling the port we send all the messages from the mMessages 133 // though the actor. 134 eStateDisentangled, 135 136 // We are here if Close() has been called. We are disentangled but we can 137 // still send pending messages. 138 eStateDisentangledForClose 139 }; 140 141 void Initialize(const nsID& aUUID, const nsID& aDestinationUUID, 142 uint32_t aSequenceID, bool mNeutered, State aState, 143 ErrorResult& aRv); 144 145 void ConnectToPBackground(); 146 147 // Dispatch events from the Message Queue using a nsRunnable. 148 void Dispatch(); 149 150 void StartDisentangling(); 151 void Disentangle(); 152 153 void RemoveDocFromBFCache(); 154 155 void CloseInternal(bool aSoftly); 156 157 // This method is meant to keep alive the MessagePort when this object is 158 // creating the actor and until the actor is entangled. 159 // We release the object when the port is closed or disentangled. 160 void UpdateMustKeepAlive(); 161 IsCertainlyAliveForCC()162 bool IsCertainlyAliveForCC() const override 163 { 164 return mIsKeptAlive; 165 } 166 167 nsAutoPtr<workers::WorkerHolder> mWorkerHolder; 168 169 RefPtr<PostMessageRunnable> mPostMessageRunnable; 170 171 RefPtr<MessagePortChild> mActor; 172 173 RefPtr<MessagePort> mUnshippedEntangledPort; 174 175 nsTArray<RefPtr<SharedMessagePortMessage>> mMessages; 176 nsTArray<RefPtr<SharedMessagePortMessage>> mMessagesForTheOtherPort; 177 178 nsAutoPtr<MessagePortIdentifier> mIdentifier; 179 180 uint64_t mInnerID; 181 182 State mState; 183 184 bool mMessageQueueEnabled; 185 186 bool mIsKeptAlive; 187 }; 188 189 } // namespace dom 190 } // namespace mozilla 191 192 #endif // mozilla_dom_MessagePort_h 193