mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 13:21:28 +00:00

The change to MessageChannel::Clear() makes mLink get cleared before we call ~ThreadLink. This causes a race because Clear() is not holding the monitor. To work around this, I introduced a new method PrepareToDestroy() that handles the ThreadLink splitting. Once the ThreadLinks are split, MessageChannel can clear mLink without a race. An alternative approach would be to hold the monitor in Clear() before mLink is cleared, but then we'd end up acquiring the lock when we didn't need to in the case where mLink is a ProcessLink. Differential Revision: https://phabricator.services.mozilla.com/D79185
127 lines
3.7 KiB
C++
127 lines
3.7 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vim: sw=2 ts=4 et :
|
|
*/
|
|
/* 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 ipc_glue_MessageLink_h
|
|
#define ipc_glue_MessageLink_h 1
|
|
|
|
#include "base/basictypes.h"
|
|
#include "base/message_loop.h"
|
|
|
|
#include "mozilla/WeakPtr.h"
|
|
#include "mozilla/UniquePtr.h"
|
|
#include "mozilla/ipc/Transport.h"
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
class MessageChannel;
|
|
|
|
struct HasResultCodes {
|
|
enum Result {
|
|
MsgProcessed,
|
|
MsgDropped,
|
|
MsgNotKnown,
|
|
MsgNotAllowed,
|
|
MsgPayloadError,
|
|
MsgProcessingError,
|
|
MsgRouteError,
|
|
MsgValueError
|
|
};
|
|
};
|
|
|
|
enum Side : uint8_t { ParentSide, ChildSide, UnknownSide };
|
|
|
|
class MessageLink {
|
|
public:
|
|
typedef IPC::Message Message;
|
|
|
|
explicit MessageLink(MessageChannel* aChan);
|
|
virtual ~MessageLink();
|
|
|
|
// This is called immediately before the MessageChannel destroys its
|
|
// MessageLink. See the implementation in ThreadLink for details.
|
|
virtual void PrepareToDestroy(){};
|
|
|
|
// n.b.: These methods all require that the channel monitor is
|
|
// held when they are invoked.
|
|
virtual void SendMessage(mozilla::UniquePtr<Message> msg) = 0;
|
|
virtual void SendClose() = 0;
|
|
|
|
virtual bool Unsound_IsClosed() const = 0;
|
|
virtual uint32_t Unsound_NumQueuedMessages() const = 0;
|
|
|
|
protected:
|
|
MessageChannel* mChan;
|
|
};
|
|
|
|
class ProcessLink : public MessageLink, public Transport::Listener {
|
|
void OnCloseChannel();
|
|
void OnChannelOpened();
|
|
void OnTakeConnectedChannel();
|
|
|
|
void AssertIOThread() const {
|
|
MOZ_ASSERT(mIOLoop == MessageLoop::current(), "not on I/O thread!");
|
|
}
|
|
|
|
public:
|
|
explicit ProcessLink(MessageChannel* chan);
|
|
virtual ~ProcessLink();
|
|
|
|
// The ProcessLink will register itself as the IPC::Channel::Listener on the
|
|
// transport passed here. If the transport already has a listener registered
|
|
// then a listener chain will be established (the ProcessLink listener
|
|
// methods will be called first and may call some methods on the original
|
|
// listener as well). Once the channel is closed (either via normal shutdown
|
|
// or a pipe error) the chain will be destroyed and the original listener
|
|
// will again be registered.
|
|
void Open(UniquePtr<Transport> aTransport, MessageLoop* aIOLoop, Side aSide);
|
|
|
|
// Run on the I/O thread, only when using inter-process link.
|
|
// These methods acquire the monitor and forward to the
|
|
// similarly named methods in AsyncChannel below
|
|
// (OnMessageReceivedFromLink(), etc)
|
|
virtual void OnMessageReceived(Message&& msg) override;
|
|
virtual void OnChannelConnected(int32_t peer_pid) override;
|
|
virtual void OnChannelError() override;
|
|
|
|
virtual void SendMessage(mozilla::UniquePtr<Message> msg) override;
|
|
virtual void SendClose() override;
|
|
|
|
virtual bool Unsound_IsClosed() const override;
|
|
virtual uint32_t Unsound_NumQueuedMessages() const override;
|
|
|
|
protected:
|
|
void OnChannelConnectError();
|
|
|
|
protected:
|
|
UniquePtr<Transport> mTransport;
|
|
MessageLoop* mIOLoop; // thread where IO happens
|
|
Transport::Listener* mExistingListener; // channel's previous listener
|
|
};
|
|
|
|
class ThreadLink : public MessageLink {
|
|
public:
|
|
ThreadLink(MessageChannel* aChan, MessageChannel* aTargetChan);
|
|
virtual ~ThreadLink() = default;
|
|
|
|
virtual void PrepareToDestroy() override;
|
|
|
|
virtual void SendMessage(mozilla::UniquePtr<Message> msg) override;
|
|
virtual void SendClose() override;
|
|
|
|
virtual bool Unsound_IsClosed() const override;
|
|
virtual uint32_t Unsound_NumQueuedMessages() const override;
|
|
|
|
protected:
|
|
MessageChannel* mTargetChan;
|
|
};
|
|
|
|
} // namespace ipc
|
|
} // namespace mozilla
|
|
|
|
#endif // ifndef ipc_glue_MessageLink_h
|