DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (c584e29f6ac2)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_MessagePort_h
#define mozilla_dom_MessagePort_h

#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"

#ifdef XP_WIN
#  undef PostMessage
#endif

class nsIGlobalObject;

namespace mozilla {
namespace dom {

class ClonedMessageData;
class MessagePortChild;
class MessagePortIdentifier;
struct PostMessageOptions;
class PostMessageRunnable;
class SharedMessagePortMessage;
class StrongWorkerRef;

class MessagePort final : public DOMEventTargetHelper {
  friend class PostMessageRunnable;

 public:
  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper)

  static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal,
                                              const nsID& aUUID,
                                              const nsID& aDestinationUUID,
                                              ErrorResult& aRv);

  static already_AddRefed<MessagePort> Create(
      nsIGlobalObject* aGlobal, const MessagePortIdentifier& aIdentifier,
      ErrorResult& aRv);

  // For IPC.
  static void ForceClose(const MessagePortIdentifier& aIdentifier);

  virtual JSObject* WrapObject(JSContext* aCx,
                               JS::Handle<JSObject*> aGivenProto) override;

  void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                   const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);

  void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                   const PostMessageOptions& aOptions, ErrorResult& aRv);

  void Start();

  void Close();

  EventHandlerNonNull* GetOnmessage();

  void SetOnmessage(EventHandlerNonNull* aCallback);

  IMPL_EVENT_HANDLER(messageerror)

  // Non WebIDL methods

  void UnshippedEntangle(MessagePort* aEntangledPort);

  bool CanBeCloned() const { return !mHasBeenTransferredOrClosed; }

  void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);

  void CloseForced();

  // These methods are useful for MessagePortChild

  void Entangled(nsTArray<ClonedMessageData>& aMessages);
  void MessagesReceived(nsTArray<ClonedMessageData>& aMessages);
  void StopSendingDataConfirmed();
  void Closed();

 private:
  enum State {
    // When a port is created by a MessageChannel it is entangled with the
    // other. They both run on the same thread, same event loop and the
    // messages are added to the queues without using PBackground actors.
    // When one of the port is shipped, the state is changed to
    // StateEntangling.
    eStateUnshippedEntangled,

    // If the port is closed or cloned when we are in this state, we go in one
    // of the following 2 steps. EntanglingForClose or ForDisentangle.
    eStateEntangling,

    // We are not fully entangled yet but are already disentangled.
    eStateEntanglingForDisentangle,

    // We are not fully entangled yet but are already closed.
    eStateEntanglingForClose,

    // When entangled() is received we send all the messages in the
    // mMessagesForTheOtherPort to the actor and we change the state to
    // StateEntangled. At this point the port is entangled with the other. We
    // send and receive messages.
    // If the port queue is not enabled, the received messages are stored in
    // the mMessages.
    eStateEntangled,

    // When the port is cloned or disentangled we want to stop receiving
    // messages. We call 'SendStopSendingData' to the actor and we wait for an
    // answer. All the messages received between now and the
    // 'StopSendingDataComfirmed are queued in the mMessages but not
    // dispatched.
    eStateDisentangling,

    // When 'StopSendingDataConfirmed' is received, we can disentangle the port
    // calling SendDisentangle in the actor because we are 100% sure that we
    // don't receive any other message, so nothing will be lost.
    // Disentangling the port we send all the messages from the mMessages
    // though the actor.
    eStateDisentangled,

    // We are here if Close() has been called. We are disentangled but we can
    // still send pending messages.
    eStateDisentangledForClose
  };

  explicit MessagePort(nsIGlobalObject* aGlobal, State aState);
  ~MessagePort();

  void DisconnectFromOwner() override;

  void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
                  uint32_t aSequenceID, bool aNeutered, ErrorResult& aRv);

  bool ConnectToPBackground();

  // Dispatch events from the Message Queue using a nsRunnable.
  void Dispatch();

  void DispatchError();

  void StartDisentangling();
  void Disentangle();

  void RemoveDocFromBFCache();

  void CloseInternal(bool aSoftly);

  // This method is meant to keep alive the MessagePort when this object is
  // creating the actor and until the actor is entangled.
  // We release the object when the port is closed or disentangled.
  void UpdateMustKeepAlive();

  bool IsCertainlyAliveForCC() const override { return mIsKeptAlive; }

  RefPtr<StrongWorkerRef> mWorkerRef;

  RefPtr<PostMessageRunnable> mPostMessageRunnable;

  RefPtr<MessagePortChild> mActor;

  RefPtr<MessagePort> mUnshippedEntangledPort;

  nsTArray<RefPtr<SharedMessagePortMessage>> mMessages;
  nsTArray<RefPtr<SharedMessagePortMessage>> mMessagesForTheOtherPort;

  nsAutoPtr<MessagePortIdentifier> mIdentifier;

  State mState;

  bool mMessageQueueEnabled;

  bool mIsKeptAlive;

  // mHasBeenTransferredOrClosed is used to know if this port has been manually
  // closed or transferred via postMessage. Note that if the entangled port is
  // closed, this port is closed as well (see mState) but, just because close()
  // has not been called directly, by spec, this port can still be transferred.
  bool mHasBeenTransferredOrClosed;
};

}  // namespace dom
}  // namespace mozilla

#endif  // mozilla_dom_MessagePort_h