2013-09-28 05:42:08 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* vim: sw=4 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/. */
|
|
|
|
|
|
|
|
#include "mozilla/ipc/MessageChannel.h"
|
2014-12-06 20:51:14 +03:00
|
|
|
|
2014-01-11 00:58:31 +04:00
|
|
|
#include "mozilla/Assertions.h"
|
|
|
|
#include "mozilla/DebugOnly.h"
|
2017-03-16 12:36:15 +03:00
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
|
|
|
#include "mozilla/ipc/ProtocolUtils.h"
|
|
|
|
#include "mozilla/Logging.h"
|
2014-01-11 00:58:31 +04:00
|
|
|
#include "mozilla/Move.h"
|
2018-04-27 03:14:22 +03:00
|
|
|
#include "mozilla/ScopeExit.h"
|
2016-08-15 09:43:21 +03:00
|
|
|
#include "mozilla/Sprintf.h"
|
2015-07-01 03:12:30 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2017-01-31 11:28:41 +03:00
|
|
|
#include "mozilla/TimeStamp.h"
|
2017-03-11 04:01:38 +03:00
|
|
|
#include "nsAppRunner.h"
|
2017-09-21 22:52:37 +03:00
|
|
|
#include "mozilla/UniquePtr.h"
|
2016-06-07 23:10:18 +03:00
|
|
|
#include "nsAutoPtr.h"
|
2013-09-28 05:42:08 +04:00
|
|
|
#include "nsDebug.h"
|
2014-02-27 01:36:35 +04:00
|
|
|
#include "nsISupportsImpl.h"
|
2014-08-06 08:44:42 +04:00
|
|
|
#include "nsContentUtils.h"
|
2017-01-31 11:28:41 +03:00
|
|
|
#include <math.h>
|
2014-08-22 21:02:47 +04:00
|
|
|
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
#include "GeckoTaskTracer.h"
|
|
|
|
using namespace mozilla::tasktracer;
|
|
|
|
#endif
|
|
|
|
|
2013-11-22 22:53:02 +04:00
|
|
|
// Undo the damage done by mozzconf.h
|
|
|
|
#undef compress
|
|
|
|
|
2016-08-05 22:00:19 +03:00
|
|
|
static mozilla::LazyLogModule sLogModule("ipc");
|
2016-01-20 04:23:28 +03:00
|
|
|
#define IPC_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
|
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
/*
|
|
|
|
* IPC design:
|
|
|
|
*
|
|
|
|
* There are three kinds of messages: async, sync, and intr. Sync and intr
|
2016-10-01 02:20:50 +03:00
|
|
|
* messages are blocking.
|
2014-10-08 08:32:45 +04:00
|
|
|
*
|
|
|
|
* Terminology: To dispatch a message Foo is to run the RecvFoo code for
|
|
|
|
* it. This is also called "handling" the message.
|
|
|
|
*
|
2016-10-01 02:20:50 +03:00
|
|
|
* Sync and async messages can sometimes "nest" inside other sync messages
|
|
|
|
* (i.e., while waiting for the sync reply, we can dispatch the inner
|
|
|
|
* message). Intr messages cannot nest. The three possible nesting levels are
|
|
|
|
* NOT_NESTED, NESTED_INSIDE_SYNC, and NESTED_INSIDE_CPOW. The intended uses
|
|
|
|
* are:
|
|
|
|
* NOT_NESTED - most messages.
|
|
|
|
* NESTED_INSIDE_SYNC - CPOW-related messages, which are always sync
|
|
|
|
* and can go in either direction.
|
|
|
|
* NESTED_INSIDE_CPOW - messages where we don't want to dispatch
|
|
|
|
* incoming CPOWs while waiting for the response.
|
|
|
|
* These nesting levels are ordered: NOT_NESTED, NESTED_INSIDE_SYNC,
|
|
|
|
* NESTED_INSIDE_CPOW. Async messages cannot be NESTED_INSIDE_SYNC but they can
|
|
|
|
* be NESTED_INSIDE_CPOW.
|
2014-10-08 08:32:45 +04:00
|
|
|
*
|
2016-10-01 02:20:50 +03:00
|
|
|
* To avoid jank, the parent process is not allowed to send NOT_NESTED sync messages.
|
|
|
|
* When a process is waiting for a response to a sync message
|
2015-07-01 03:09:38 +03:00
|
|
|
* M0, it will dispatch an incoming message M if:
|
2016-10-01 02:20:50 +03:00
|
|
|
* 1. M has a higher nesting level than M0, or
|
|
|
|
* 2. if M has the same nesting level as M0 and we're in the child, or
|
|
|
|
* 3. if M has the same nesting level as M0 and it was sent by the other side
|
|
|
|
* while dispatching M0.
|
|
|
|
* The idea is that messages with higher nesting should take precendence. The
|
|
|
|
* purpose of rule 2 is to handle a race where both processes send to each other
|
|
|
|
* simultaneously. In this case, we resolve the race in favor of the parent (so
|
|
|
|
* the child dispatches first).
|
2014-10-08 08:32:45 +04:00
|
|
|
*
|
2015-07-01 03:09:38 +03:00
|
|
|
* Messages satisfy the following properties:
|
2014-10-08 08:32:45 +04:00
|
|
|
* A. When waiting for a response to a sync message, we won't dispatch any
|
2016-10-01 02:20:50 +03:00
|
|
|
* messages of nesting level.
|
|
|
|
* B. Messages of the same nesting level will be dispatched roughly in the
|
2014-10-08 08:32:45 +04:00
|
|
|
* order they were sent. The exception is when the parent and child send
|
|
|
|
* sync messages to each other simulataneously. In this case, the parent's
|
|
|
|
* message is dispatched first. While it is dispatched, the child may send
|
|
|
|
* further nested messages, and these messages may be dispatched before the
|
|
|
|
* child's original message. We can consider ordering to be preserved here
|
|
|
|
* because we pretend that the child's original message wasn't sent until
|
|
|
|
* after the parent's message is finished being dispatched.
|
|
|
|
*
|
2015-07-01 03:09:38 +03:00
|
|
|
* When waiting for a sync message reply, we dispatch an async message only if
|
2016-10-01 02:20:50 +03:00
|
|
|
* it is NESTED_INSIDE_CPOW. Normally NESTED_INSIDE_CPOW async
|
|
|
|
* messages are sent only from the child. However, the parent can send
|
|
|
|
* NESTED_INSIDE_CPOW async messages when it is creating a bridged protocol.
|
2015-07-01 03:09:38 +03:00
|
|
|
*
|
2016-10-01 02:20:50 +03:00
|
|
|
* Intr messages are blocking and can nest, but they don't participate in the
|
|
|
|
* nesting levels. While waiting for an intr response, all incoming messages are
|
|
|
|
* dispatched until a response is received. When two intr messages race with
|
2014-10-08 08:32:45 +04:00
|
|
|
* each other, a similar scheme is used to ensure that one side wins. The
|
|
|
|
* winning side is chosen based on the message type.
|
|
|
|
*
|
|
|
|
* Intr messages differ from sync messages in that, while sending an intr
|
|
|
|
* message, we may dispatch an async message. This causes some additional
|
|
|
|
* complexity. One issue is that replies can be received out of order. It's also
|
|
|
|
* more difficult to determine whether one message is nested inside
|
|
|
|
* another. Consequently, intr handling uses mOutOfTurnReplies and
|
|
|
|
* mRemoteStackDepthGuess, which are not needed for sync messages.
|
|
|
|
*/
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
using namespace mozilla;
|
2016-08-05 22:00:19 +03:00
|
|
|
using namespace mozilla::ipc;
|
2013-09-28 05:42:08 +04:00
|
|
|
using namespace std;
|
|
|
|
|
2014-12-06 20:51:14 +03:00
|
|
|
using mozilla::dom::AutoNoJSAPI;
|
|
|
|
using mozilla::dom::ScriptSettingsInitialized;
|
2013-09-28 05:42:08 +04:00
|
|
|
using mozilla::MonitorAutoLock;
|
|
|
|
using mozilla::MonitorAutoUnlock;
|
|
|
|
|
|
|
|
#define IPC_ASSERT(_cond, ...) \
|
|
|
|
do { \
|
|
|
|
if (!(_cond)) \
|
|
|
|
DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__); \
|
|
|
|
} while (0)
|
|
|
|
|
2015-10-07 21:13:48 +03:00
|
|
|
static MessageChannel* gParentProcessBlocker;
|
2014-08-06 08:43:36 +04:00
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace ipc {
|
|
|
|
|
2017-05-04 11:34:20 +03:00
|
|
|
static const uint32_t kMinTelemetryMessageSize = 4096;
|
2016-03-31 01:25:54 +03:00
|
|
|
|
2017-03-08 02:02:39 +03:00
|
|
|
// Note: we round the time we spend to the nearest millisecond. So a min value
|
|
|
|
// of 1 ms actually captures from 500us and above.
|
|
|
|
static const uint32_t kMinTelemetryIPCWriteLatencyMs = 1;
|
|
|
|
|
2017-01-31 11:28:41 +03:00
|
|
|
// Note: we round the time we spend waiting for a response to the nearest
|
|
|
|
// millisecond. So a min value of 1 ms actually captures from 500us and above.
|
2017-05-17 22:38:59 +03:00
|
|
|
// This is used for both the sending and receiving side telemetry for sync IPC,
|
|
|
|
// (IPC_SYNC_MAIN_LATENCY_MS and IPC_SYNC_RECEIVE_MS).
|
2017-01-31 11:28:41 +03:00
|
|
|
static const uint32_t kMinTelemetrySyncIPCLatencyMs = 1;
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
const int32_t MessageChannel::kNoTimeout = INT32_MIN;
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool MessageChannel::sIsPumpingMessages = false;
|
|
|
|
|
2014-01-11 00:58:31 +04:00
|
|
|
enum Direction
|
|
|
|
{
|
|
|
|
IN_MESSAGE,
|
|
|
|
OUT_MESSAGE
|
|
|
|
};
|
|
|
|
|
|
|
|
class MessageChannel::InterruptFrame
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
enum Semantics
|
|
|
|
{
|
|
|
|
INTR_SEMS,
|
|
|
|
SYNC_SEMS,
|
|
|
|
ASYNC_SEMS
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
InterruptFrame(Direction direction, const Message* msg)
|
2016-01-21 06:00:01 +03:00
|
|
|
: mMessageName(msg->name()),
|
2014-01-11 00:58:31 +04:00
|
|
|
mMessageRoutingId(msg->routing_id()),
|
|
|
|
mMesageSemantics(msg->is_interrupt() ? INTR_SEMS :
|
|
|
|
msg->is_sync() ? SYNC_SEMS :
|
|
|
|
ASYNC_SEMS),
|
|
|
|
mDirection(direction),
|
|
|
|
mMoved(false)
|
|
|
|
{
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mMessageName);
|
2014-01-11 00:58:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
InterruptFrame(InterruptFrame&& aOther)
|
|
|
|
{
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aOther.mMessageName);
|
2014-01-11 00:58:31 +04:00
|
|
|
mMessageName = aOther.mMessageName;
|
|
|
|
aOther.mMessageName = nullptr;
|
2016-02-09 12:21:39 +03:00
|
|
|
mMoved = aOther.mMoved;
|
2014-01-11 00:58:31 +04:00
|
|
|
aOther.mMoved = true;
|
|
|
|
|
|
|
|
mMessageRoutingId = aOther.mMessageRoutingId;
|
|
|
|
mMesageSemantics = aOther.mMesageSemantics;
|
|
|
|
mDirection = aOther.mDirection;
|
|
|
|
}
|
|
|
|
|
|
|
|
~InterruptFrame()
|
|
|
|
{
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mMessageName || mMoved);
|
2014-01-11 00:58:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
InterruptFrame& operator=(InterruptFrame&& aOther)
|
|
|
|
{
|
2015-06-29 23:43:42 +03:00
|
|
|
MOZ_RELEASE_ASSERT(&aOther != this);
|
2014-01-11 00:58:31 +04:00
|
|
|
this->~InterruptFrame();
|
2018-05-30 22:15:35 +03:00
|
|
|
new (this) InterruptFrame(std::move(aOther));
|
2014-01-11 00:58:31 +04:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsInterruptIncall() const
|
|
|
|
{
|
|
|
|
return INTR_SEMS == mMesageSemantics && IN_MESSAGE == mDirection;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsInterruptOutcall() const
|
|
|
|
{
|
|
|
|
return INTR_SEMS == mMesageSemantics && OUT_MESSAGE == mDirection;
|
|
|
|
}
|
|
|
|
|
2015-01-17 05:34:47 +03:00
|
|
|
bool IsOutgoingSync() const {
|
|
|
|
return (mMesageSemantics == INTR_SEMS || mMesageSemantics == SYNC_SEMS) &&
|
|
|
|
mDirection == OUT_MESSAGE;
|
|
|
|
}
|
|
|
|
|
2014-01-11 00:58:31 +04:00
|
|
|
void Describe(int32_t* id, const char** dir, const char** sems,
|
|
|
|
const char** name) const
|
|
|
|
{
|
|
|
|
*id = mMessageRoutingId;
|
|
|
|
*dir = (IN_MESSAGE == mDirection) ? "in" : "out";
|
|
|
|
*sems = (INTR_SEMS == mMesageSemantics) ? "intr" :
|
|
|
|
(SYNC_SEMS == mMesageSemantics) ? "sync" :
|
|
|
|
"async";
|
|
|
|
*name = mMessageName;
|
|
|
|
}
|
|
|
|
|
2015-02-19 09:05:54 +03:00
|
|
|
int32_t GetRoutingId() const
|
|
|
|
{
|
|
|
|
return mMessageRoutingId;
|
|
|
|
}
|
|
|
|
|
2014-01-11 00:58:31 +04:00
|
|
|
private:
|
|
|
|
const char* mMessageName;
|
|
|
|
int32_t mMessageRoutingId;
|
|
|
|
Semantics mMesageSemantics;
|
|
|
|
Direction mDirection;
|
2016-02-05 03:09:11 +03:00
|
|
|
bool mMoved;
|
2014-01-11 00:58:31 +04:00
|
|
|
|
|
|
|
// Disable harmful methods.
|
2015-01-07 02:35:02 +03:00
|
|
|
InterruptFrame(const InterruptFrame& aOther) = delete;
|
|
|
|
InterruptFrame& operator=(const InterruptFrame&) = delete;
|
2014-01-11 00:58:31 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
class MOZ_STACK_CLASS MessageChannel::CxxStackFrame
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CxxStackFrame(MessageChannel& that, Direction direction, const Message* msg)
|
|
|
|
: mThat(that)
|
|
|
|
{
|
|
|
|
mThat.AssertWorkerThread();
|
|
|
|
|
|
|
|
if (mThat.mCxxStackFrames.empty())
|
|
|
|
mThat.EnteredCxxStack();
|
|
|
|
|
2016-01-14 17:19:24 +03:00
|
|
|
if (!mThat.mCxxStackFrames.append(InterruptFrame(direction, msg)))
|
|
|
|
MOZ_CRASH();
|
2014-01-11 00:58:31 +04:00
|
|
|
|
|
|
|
const InterruptFrame& frame = mThat.mCxxStackFrames.back();
|
|
|
|
|
|
|
|
if (frame.IsInterruptIncall())
|
|
|
|
mThat.EnteredCall();
|
|
|
|
|
2015-01-17 05:34:47 +03:00
|
|
|
if (frame.IsOutgoingSync())
|
|
|
|
mThat.EnteredSyncSend();
|
|
|
|
|
2014-01-11 00:58:31 +04:00
|
|
|
mThat.mSawInterruptOutMsg |= frame.IsInterruptOutcall();
|
|
|
|
}
|
|
|
|
|
|
|
|
~CxxStackFrame() {
|
|
|
|
mThat.AssertWorkerThread();
|
|
|
|
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mThat.mCxxStackFrames.empty());
|
2014-01-11 00:58:31 +04:00
|
|
|
|
2015-01-17 05:34:47 +03:00
|
|
|
const InterruptFrame& frame = mThat.mCxxStackFrames.back();
|
|
|
|
bool exitingSync = frame.IsOutgoingSync();
|
|
|
|
bool exitingCall = frame.IsInterruptIncall();
|
2014-01-11 00:58:31 +04:00
|
|
|
mThat.mCxxStackFrames.shrinkBy(1);
|
|
|
|
|
|
|
|
bool exitingStack = mThat.mCxxStackFrames.empty();
|
|
|
|
|
2016-08-10 11:53:00 +03:00
|
|
|
// According how lifetime is declared, mListener on MessageChannel
|
|
|
|
// lives longer than MessageChannel itself. Hence is expected to
|
|
|
|
// be alive. There is nothing to even assert here, there is no place
|
|
|
|
// we would be nullifying mListener on MessageChannel.
|
2014-01-11 00:58:31 +04:00
|
|
|
|
|
|
|
if (exitingCall)
|
|
|
|
mThat.ExitedCall();
|
|
|
|
|
2015-01-17 05:34:47 +03:00
|
|
|
if (exitingSync)
|
|
|
|
mThat.ExitedSyncSend();
|
|
|
|
|
2014-01-11 00:58:31 +04:00
|
|
|
if (exitingStack)
|
|
|
|
mThat.ExitedCxxStack();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
MessageChannel& mThat;
|
|
|
|
|
|
|
|
// Disable harmful methods.
|
2015-01-07 02:35:02 +03:00
|
|
|
CxxStackFrame() = delete;
|
|
|
|
CxxStackFrame(const CxxStackFrame&) = delete;
|
|
|
|
CxxStackFrame& operator=(const CxxStackFrame&) = delete;
|
2014-01-11 00:58:31 +04:00
|
|
|
};
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
class AutoEnterTransaction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit AutoEnterTransaction(MessageChannel *aChan,
|
|
|
|
int32_t aMsgSeqno,
|
|
|
|
int32_t aTransactionID,
|
2016-10-01 02:20:50 +03:00
|
|
|
int aNestedLevel)
|
2016-02-24 02:36:06 +03:00
|
|
|
: mChan(aChan),
|
|
|
|
mActive(true),
|
|
|
|
mOutgoing(true),
|
2016-10-01 02:20:50 +03:00
|
|
|
mNestedLevel(aNestedLevel),
|
2016-02-24 02:36:06 +03:00
|
|
|
mSeqno(aMsgSeqno),
|
|
|
|
mTransaction(aTransactionID),
|
|
|
|
mNext(mChan->mTransactionStack)
|
|
|
|
{
|
|
|
|
mChan->mMonitor->AssertCurrentThreadOwns();
|
|
|
|
mChan->mTransactionStack = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit AutoEnterTransaction(MessageChannel *aChan, const IPC::Message &aMessage)
|
|
|
|
: mChan(aChan),
|
|
|
|
mActive(true),
|
|
|
|
mOutgoing(false),
|
2016-10-01 02:20:50 +03:00
|
|
|
mNestedLevel(aMessage.nested_level()),
|
2016-02-24 02:36:06 +03:00
|
|
|
mSeqno(aMessage.seqno()),
|
|
|
|
mTransaction(aMessage.transaction_id()),
|
|
|
|
mNext(mChan->mTransactionStack)
|
|
|
|
{
|
|
|
|
mChan->mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
if (!aMessage.is_sync()) {
|
|
|
|
mActive = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChan->mTransactionStack = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~AutoEnterTransaction() {
|
|
|
|
mChan->mMonitor->AssertCurrentThreadOwns();
|
|
|
|
if (mActive) {
|
|
|
|
mChan->mTransactionStack = mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Cancel() {
|
|
|
|
AutoEnterTransaction *cur = mChan->mTransactionStack;
|
|
|
|
MOZ_RELEASE_ASSERT(cur == this);
|
2016-10-01 02:20:50 +03:00
|
|
|
while (cur && cur->mNestedLevel != IPC::Message::NOT_NESTED) {
|
2016-02-24 02:36:06 +03:00
|
|
|
// Note that, in the following situation, we will cancel multiple
|
|
|
|
// transactions:
|
2016-10-01 02:20:50 +03:00
|
|
|
// 1. Parent sends NESTED_INSIDE_SYNC message P1 to child.
|
|
|
|
// 2. Child sends NESTED_INSIDE_SYNC message C1 to child.
|
2016-02-24 02:36:06 +03:00
|
|
|
// 3. Child dispatches P1, parent blocks.
|
|
|
|
// 4. Child cancels.
|
|
|
|
// In this case, both P1 and C1 are cancelled. The parent will
|
|
|
|
// remove C1 from its queue when it gets the cancellation message.
|
|
|
|
MOZ_RELEASE_ASSERT(cur->mActive);
|
|
|
|
cur->mActive = false;
|
|
|
|
cur = cur->mNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChan->mTransactionStack = cur;
|
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(IsComplete());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AwaitingSyncReply() const {
|
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
|
|
|
if (mOutgoing) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return mNext ? mNext->AwaitingSyncReply() : false;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
int AwaitingSyncReplyNestedLevel() const {
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
|
|
|
if (mOutgoing) {
|
2016-10-01 02:20:50 +03:00
|
|
|
return mNestedLevel;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
2016-10-01 02:20:50 +03:00
|
|
|
return mNext ? mNext->AwaitingSyncReplyNestedLevel() : 0;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DispatchingSyncMessage() const {
|
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
|
|
|
if (!mOutgoing) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return mNext ? mNext->DispatchingSyncMessage() : false;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
int DispatchingSyncMessageNestedLevel() const {
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
|
|
|
if (!mOutgoing) {
|
2016-10-01 02:20:50 +03:00
|
|
|
return mNestedLevel;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
2016-10-01 02:20:50 +03:00
|
|
|
return mNext ? mNext->DispatchingSyncMessageNestedLevel() : 0;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
int NestedLevel() const {
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
2016-10-01 02:20:50 +03:00
|
|
|
return mNestedLevel;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t SequenceNumber() const {
|
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
|
|
|
return mSeqno;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t TransactionID() const {
|
|
|
|
MOZ_RELEASE_ASSERT(mActive);
|
|
|
|
return mTransaction;
|
|
|
|
}
|
|
|
|
|
2016-05-17 00:02:43 +03:00
|
|
|
void ReceivedReply(IPC::Message&& aMessage) {
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aMessage.seqno() == mSeqno);
|
|
|
|
MOZ_RELEASE_ASSERT(aMessage.transaction_id() == mTransaction);
|
|
|
|
MOZ_RELEASE_ASSERT(!mReply);
|
|
|
|
IPC_LOG("Reply received on worker thread: seqno=%d", mSeqno);
|
2018-05-30 22:15:35 +03:00
|
|
|
mReply = MakeUnique<IPC::Message>(std::move(aMessage));
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(IsComplete());
|
|
|
|
}
|
|
|
|
|
2016-05-17 00:02:43 +03:00
|
|
|
void HandleReply(IPC::Message&& aMessage) {
|
2016-02-24 02:36:06 +03:00
|
|
|
AutoEnterTransaction *cur = mChan->mTransactionStack;
|
|
|
|
MOZ_RELEASE_ASSERT(cur == this);
|
|
|
|
while (cur) {
|
|
|
|
MOZ_RELEASE_ASSERT(cur->mActive);
|
|
|
|
if (aMessage.seqno() == cur->mSeqno) {
|
2018-05-30 22:15:35 +03:00
|
|
|
cur->ReceivedReply(std::move(aMessage));
|
2016-02-24 02:36:06 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
cur = cur->mNext;
|
|
|
|
MOZ_RELEASE_ASSERT(cur);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsComplete() {
|
|
|
|
return !mActive || mReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsOutgoing() {
|
|
|
|
return mOutgoing;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsCanceled() {
|
|
|
|
return !mActive;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsBottom() const {
|
|
|
|
return !mNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsError() {
|
|
|
|
MOZ_RELEASE_ASSERT(mReply);
|
|
|
|
return mReply->is_reply_error();
|
|
|
|
}
|
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<IPC::Message> GetReply() {
|
2018-05-30 22:15:35 +03:00
|
|
|
return std::move(mReply);
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
MessageChannel *mChan;
|
|
|
|
|
|
|
|
// Active is true if this transaction is on the mChan->mTransactionStack
|
|
|
|
// stack. Generally we're not on the stack if the transaction was canceled
|
|
|
|
// or if it was for a message that doesn't require transactions (an async
|
|
|
|
// message).
|
|
|
|
bool mActive;
|
|
|
|
|
|
|
|
// Is this stack frame for an outgoing message?
|
|
|
|
bool mOutgoing;
|
|
|
|
|
|
|
|
// Properties of the message being sent/received.
|
2016-10-01 02:20:50 +03:00
|
|
|
int mNestedLevel;
|
2016-02-24 02:36:06 +03:00
|
|
|
int32_t mSeqno;
|
|
|
|
int32_t mTransaction;
|
|
|
|
|
|
|
|
// Next item in mChan->mTransactionStack.
|
|
|
|
AutoEnterTransaction *mNext;
|
|
|
|
|
|
|
|
// Pointer the a reply received for this message, if one was received.
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<IPC::Message> mReply;
|
2016-02-24 02:36:06 +03:00
|
|
|
};
|
|
|
|
|
2017-11-16 23:12:06 +03:00
|
|
|
class PendingResponseReporter final : public nsIMemoryReporter
|
2017-03-16 12:36:15 +03:00
|
|
|
{
|
2017-11-16 23:12:06 +03:00
|
|
|
~PendingResponseReporter() {}
|
2017-03-16 12:36:15 +03:00
|
|
|
public:
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
|
|
|
|
bool aAnonymize) override
|
|
|
|
{
|
|
|
|
MOZ_COLLECT_REPORT(
|
2017-11-16 23:12:06 +03:00
|
|
|
"unresolved-ipc-responses", KIND_OTHER, UNITS_COUNT, MessageChannel::gUnresolvedResponses,
|
|
|
|
"Outstanding IPC async message responses that are still not resolved.");
|
2017-03-16 12:36:15 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-11-16 23:12:06 +03:00
|
|
|
NS_IMPL_ISUPPORTS(PendingResponseReporter, nsIMemoryReporter)
|
2017-03-16 12:36:15 +03:00
|
|
|
|
2017-11-16 23:12:06 +03:00
|
|
|
Atomic<size_t> MessageChannel::gUnresolvedResponses;
|
2017-03-16 12:36:15 +03:00
|
|
|
|
2017-03-21 00:15:44 +03:00
|
|
|
MessageChannel::MessageChannel(const char* aName,
|
|
|
|
IToplevelProtocol *aListener)
|
|
|
|
: mName(aName),
|
|
|
|
mListener(aListener),
|
2013-09-28 05:42:08 +04:00
|
|
|
mChannelState(ChannelClosed),
|
|
|
|
mSide(UnknownSide),
|
|
|
|
mLink(nullptr),
|
|
|
|
mWorkerLoop(nullptr),
|
|
|
|
mChannelErrorTask(nullptr),
|
2017-05-26 02:51:31 +03:00
|
|
|
mWorkerThread(nullptr),
|
2013-09-28 05:42:08 +04:00
|
|
|
mTimeoutMs(kNoTimeout),
|
|
|
|
mInTimeoutSecondHalf(false),
|
|
|
|
mNextSeqno(0),
|
2016-01-23 04:45:43 +03:00
|
|
|
mLastSendError(SyncSendError::SendSuccess),
|
2014-12-19 04:35:48 +03:00
|
|
|
mDispatchingAsyncMessage(false),
|
2016-10-01 02:20:50 +03:00
|
|
|
mDispatchingAsyncMessageNestedLevel(0),
|
2016-02-24 02:36:06 +03:00
|
|
|
mTransactionStack(nullptr),
|
2014-12-19 04:35:44 +03:00
|
|
|
mTimedOutMessageSeqno(0),
|
2016-10-01 02:20:50 +03:00
|
|
|
mTimedOutMessageNestedLevel(0),
|
2017-04-11 07:44:56 +03:00
|
|
|
mMaybeDeferredPendingCount(0),
|
2016-10-15 21:47:14 +03:00
|
|
|
mRemoteStackDepthGuess(0),
|
2014-03-04 21:17:01 +04:00
|
|
|
mSawInterruptOutMsg(false),
|
2014-12-30 02:12:47 +03:00
|
|
|
mIsWaitingForIncoming(false),
|
2014-08-06 08:44:42 +04:00
|
|
|
mAbortOnError(false),
|
2016-09-20 05:17:09 +03:00
|
|
|
mNotifiedChannelDone(false),
|
2014-08-21 22:13:23 +04:00
|
|
|
mFlags(REQUIRE_DEFAULT),
|
|
|
|
mPeerPidSet(false),
|
2017-06-21 23:40:18 +03:00
|
|
|
mPeerPid(-1),
|
2018-04-18 04:38:22 +03:00
|
|
|
mIsPostponingSends(false),
|
2018-05-08 17:31:44 +03:00
|
|
|
mInKillHardShutdown(false),
|
|
|
|
mBuildIDsConfirmedMatch(false)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(ipc::MessageChannel);
|
|
|
|
|
|
|
|
#ifdef OS_WIN
|
|
|
|
mTopFrame = nullptr;
|
2014-05-18 07:16:51 +04:00
|
|
|
mIsSyncWaitingOnNonMainThread = false;
|
2013-09-28 05:42:08 +04:00
|
|
|
#endif
|
|
|
|
|
2017-06-12 22:34:10 +03:00
|
|
|
mOnChannelConnectedTask = NewNonOwningCancelableRunnableMethod(
|
|
|
|
"ipc::MessageChannel::DispatchOnChannelConnected",
|
|
|
|
this,
|
|
|
|
&MessageChannel::DispatchOnChannelConnected);
|
2014-08-21 22:13:23 +04:00
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
#ifdef OS_WIN
|
2014-03-04 06:35:51 +04:00
|
|
|
mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mEvent, "CreateEvent failed! Nothing is going to work!");
|
2013-09-28 05:42:08 +04:00
|
|
|
#endif
|
2017-03-16 12:36:15 +03:00
|
|
|
|
|
|
|
static Atomic<bool> registered;
|
|
|
|
if (registered.compareExchange(false, true)) {
|
2017-11-16 23:12:06 +03:00
|
|
|
RegisterStrongMemoryReporter(new PendingResponseReporter());
|
2017-03-16 12:36:15 +03:00
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
MessageChannel::~MessageChannel()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(ipc::MessageChannel);
|
|
|
|
IPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors");
|
|
|
|
#ifdef OS_WIN
|
2016-05-04 21:03:49 +03:00
|
|
|
if (mEvent) {
|
|
|
|
BOOL ok = CloseHandle(mEvent);
|
|
|
|
mEvent = nullptr;
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
gfxDevCrash(mozilla::gfx::LogReason::MessageChannelCloseFailure) <<
|
|
|
|
"MessageChannel failed to close. GetLastError: " <<
|
|
|
|
GetLastError();
|
|
|
|
}
|
|
|
|
MOZ_RELEASE_ASSERT(ok);
|
|
|
|
} else {
|
2016-04-06 19:03:22 +03:00
|
|
|
gfxDevCrash(mozilla::gfx::LogReason::MessageChannelCloseFailure) <<
|
2016-05-04 21:03:49 +03:00
|
|
|
"MessageChannel destructor ran without an mEvent Handle";
|
2016-04-06 19:03:22 +03:00
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
#endif
|
2013-10-22 03:19:40 +04:00
|
|
|
Clear();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
MessageChannel::AssertMaybeDeferredCountCorrect()
|
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
for (MessageTask* task : mPending) {
|
|
|
|
if (!IsAlwaysDeferred(task->Msg())) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(count == mMaybeDeferredPendingCount);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
// This function returns the current transaction ID. Since the notion of a
|
|
|
|
// "current transaction" can be hard to define when messages race with each
|
|
|
|
// other and one gets canceled and the other doesn't, we require that this
|
|
|
|
// function is only called when the current transaction is known to be for a
|
2016-10-01 02:20:50 +03:00
|
|
|
// NESTED_INSIDE_SYNC message. In that case, we know for sure what the caller is
|
2016-02-24 02:36:06 +03:00
|
|
|
// looking for.
|
|
|
|
int32_t
|
2016-10-01 02:20:50 +03:00
|
|
|
MessageChannel::CurrentNestedInsideSyncTransaction() const
|
2016-02-24 02:36:06 +03:00
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
if (!mTransactionStack) {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-10-01 02:20:50 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mTransactionStack->NestedLevel() == IPC::Message::NESTED_INSIDE_SYNC);
|
2016-02-24 02:36:06 +03:00
|
|
|
return mTransactionStack->TransactionID();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::AwaitingSyncReply() const
|
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
return mTransactionStack ? mTransactionStack->AwaitingSyncReply() : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-10-01 02:20:50 +03:00
|
|
|
MessageChannel::AwaitingSyncReplyNestedLevel() const
|
2016-02-24 02:36:06 +03:00
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
2016-10-01 02:20:50 +03:00
|
|
|
return mTransactionStack ? mTransactionStack->AwaitingSyncReplyNestedLevel() : 0;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::DispatchingSyncMessage() const
|
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
return mTransactionStack ? mTransactionStack->DispatchingSyncMessage() : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-10-01 02:20:50 +03:00
|
|
|
MessageChannel::DispatchingSyncMessageNestedLevel() const
|
2016-02-24 02:36:06 +03:00
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
2016-10-01 02:20:50 +03:00
|
|
|
return mTransactionStack ? mTransactionStack->DispatchingSyncMessageNestedLevel() : 0;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
|
|
|
|
2013-11-15 00:24:18 +04:00
|
|
|
static void
|
|
|
|
PrintErrorMessage(Side side, const char* channelName, const char* msg)
|
|
|
|
{
|
|
|
|
const char *from = (side == ChildSide)
|
|
|
|
? "Child"
|
|
|
|
: ((side == ParentSide) ? "Parent" : "Unknown");
|
|
|
|
printf_stderr("\n###!!! [%s][%s] Error: %s\n\n", from, channelName, msg);
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
bool
|
|
|
|
MessageChannel::Connected() const
|
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
// The transport layer allows us to send messages before
|
|
|
|
// receiving the "connected" ack from the remote side.
|
|
|
|
return (ChannelOpening == mChannelState || ChannelConnected == mChannelState);
|
|
|
|
}
|
|
|
|
|
2014-01-31 22:43:44 +04:00
|
|
|
bool
|
|
|
|
MessageChannel::CanSend() const
|
|
|
|
{
|
2014-12-31 23:15:38 +03:00
|
|
|
if (!mMonitor) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-01-31 22:43:44 +04:00
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
return Connected();
|
|
|
|
}
|
|
|
|
|
2017-03-21 00:15:44 +03:00
|
|
|
void
|
|
|
|
MessageChannel::WillDestroyCurrentMessageLoop()
|
|
|
|
{
|
2017-09-23 02:31:07 +03:00
|
|
|
#if defined(DEBUG)
|
2018-03-12 18:11:44 +03:00
|
|
|
CrashReporter::AnnotateCrashReport(
|
|
|
|
NS_LITERAL_CSTRING("IPCFatalErrorProtocol"),
|
|
|
|
nsDependentCString(mName));
|
2017-03-21 00:15:44 +03:00
|
|
|
MOZ_CRASH("MessageLoop destroyed before MessageChannel that's bound to it");
|
|
|
|
#endif
|
2017-09-23 02:31:07 +03:00
|
|
|
|
|
|
|
// Clear mWorkerThread to avoid posting to it in the future.
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
mWorkerLoop = nullptr;
|
2017-03-21 00:15:44 +03:00
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
|
|
|
MessageChannel::Clear()
|
|
|
|
{
|
2017-05-26 02:51:31 +03:00
|
|
|
// Don't clear mWorkerThread; we use it in AssertLinkThread() and
|
2013-09-28 05:42:08 +04:00
|
|
|
// AssertWorkerThread().
|
|
|
|
//
|
|
|
|
// Also don't clear mListener. If we clear it, then sending a message
|
|
|
|
// through this channel after it's Clear()'ed can cause this process to
|
|
|
|
// crash.
|
|
|
|
//
|
|
|
|
// In practice, mListener owns the channel, so the channel gets deleted
|
|
|
|
// before mListener. But just to be safe, mListener is a weak pointer.
|
|
|
|
|
2017-03-21 01:29:05 +03:00
|
|
|
#if !defined(ANDROID)
|
2018-04-18 04:38:22 +03:00
|
|
|
// KillHard shutdowns can occur with the channel in connected state. We are
|
|
|
|
// already collecting crash dump data about KillHard shutdowns and we
|
|
|
|
// shouldn't intentionally crash here.
|
|
|
|
if (!Unsound_IsClosed() && !mInKillHardShutdown) {
|
2018-03-12 18:11:44 +03:00
|
|
|
CrashReporter::AnnotateCrashReport(
|
|
|
|
NS_LITERAL_CSTRING("IPCFatalErrorProtocol"),
|
|
|
|
nsDependentCString(mName));
|
2018-03-01 19:41:34 +03:00
|
|
|
switch (mChannelState) {
|
|
|
|
case ChannelOpening:
|
|
|
|
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
|
|
|
"(mChannelState == ChannelOpening).");
|
|
|
|
break;
|
|
|
|
case ChannelConnected:
|
|
|
|
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
|
|
|
"(mChannelState == ChannelConnected).");
|
|
|
|
break;
|
|
|
|
case ChannelTimeout:
|
|
|
|
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
|
|
|
"(mChannelState == ChannelTimeout).");
|
|
|
|
break;
|
|
|
|
case ChannelClosing:
|
|
|
|
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
|
|
|
"(mChannelState == ChannelClosing).");
|
|
|
|
break;
|
|
|
|
case ChannelError:
|
|
|
|
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
|
|
|
"(mChannelState == ChannelError).");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("MessageChannel destroyed without being closed.");
|
|
|
|
}
|
2017-03-21 01:29:05 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-10-07 21:13:48 +03:00
|
|
|
if (gParentProcessBlocker == this) {
|
|
|
|
gParentProcessBlocker = nullptr;
|
2015-06-24 03:52:01 +03:00
|
|
|
}
|
|
|
|
|
2017-03-21 00:15:44 +03:00
|
|
|
if (mWorkerLoop) {
|
|
|
|
mWorkerLoop->RemoveDestructionObserver(this);
|
|
|
|
}
|
|
|
|
|
2017-11-16 23:12:06 +03:00
|
|
|
gUnresolvedResponses -= mPendingResponses.size();
|
|
|
|
for (auto& pair : mPendingResponses) {
|
|
|
|
pair.second.get()->Reject(ResponseRejectReason::ChannelClosed);
|
2017-03-16 12:36:15 +03:00
|
|
|
}
|
2017-11-16 23:12:06 +03:00
|
|
|
mPendingResponses.clear();
|
2017-03-16 12:36:15 +03:00
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
mWorkerLoop = nullptr;
|
|
|
|
delete mLink;
|
|
|
|
mLink = nullptr;
|
|
|
|
|
2014-08-21 22:13:23 +04:00
|
|
|
mOnChannelConnectedTask->Cancel();
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
if (mChannelErrorTask) {
|
|
|
|
mChannelErrorTask->Cancel();
|
|
|
|
mChannelErrorTask = nullptr;
|
|
|
|
}
|
2014-04-24 11:26:50 +04:00
|
|
|
|
|
|
|
// Free up any memory used by pending messages.
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* task : mPending) {
|
2016-10-15 21:47:14 +03:00
|
|
|
task->Clear();
|
|
|
|
}
|
2014-04-24 11:26:50 +04:00
|
|
|
mPending.clear();
|
2016-10-15 21:47:14 +03:00
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
mMaybeDeferredPendingCount = 0;
|
|
|
|
|
2014-04-24 11:26:50 +04:00
|
|
|
mOutOfTurnReplies.clear();
|
|
|
|
while (!mDeferred.empty()) {
|
|
|
|
mDeferred.pop();
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
|
|
|
|
{
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(!mLink, "Open() called > once");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
mMonitor = new RefCountedMonitor();
|
|
|
|
mWorkerLoop = MessageLoop::current();
|
2017-05-26 02:51:31 +03:00
|
|
|
mWorkerThread = GetCurrentVirtualThread();
|
2017-03-21 00:15:44 +03:00
|
|
|
mWorkerLoop->AddDestructionObserver(this);
|
2017-05-10 22:52:20 +03:00
|
|
|
mListener->SetIsMainThreadProtocol();
|
2017-03-21 00:15:44 +03:00
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
ProcessLink *link = new ProcessLink(this);
|
|
|
|
link->Open(aTransport, aIOLoop, aSide); // :TODO: n.b.: sets mChild
|
|
|
|
mLink = link;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2017-08-03 12:21:44 +03:00
|
|
|
MessageChannel::Open(MessageChannel *aTargetChan, nsIEventTarget *aEventTarget, Side aSide)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
// Opens a connection to another thread in the same process.
|
|
|
|
|
|
|
|
// This handshake proceeds as follows:
|
|
|
|
// - Let A be the thread initiating the process (either child or parent)
|
|
|
|
// and B be the other thread.
|
|
|
|
// - A spawns thread for B, obtaining B's message loop
|
|
|
|
// - A creates ProtocolChild and ProtocolParent instances.
|
|
|
|
// Let PA be the one appropriate to A and PB the side for B.
|
|
|
|
// - A invokes PA->Open(PB, ...):
|
|
|
|
// - set state to mChannelOpening
|
|
|
|
// - this will place a work item in B's worker loop (see next bullet)
|
|
|
|
// and then spins until PB->mChannelState becomes mChannelConnected
|
|
|
|
// - meanwhile, on PB's worker loop, the work item is removed and:
|
|
|
|
// - invokes PB->SlaveOpen(PA, ...):
|
|
|
|
// - sets its state and that of PA to Connected
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(aTargetChan, "Need a target channel");
|
|
|
|
MOZ_ASSERT(ChannelClosed == mChannelState, "Not currently closed");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
CommonThreadOpenInit(aTargetChan, aSide);
|
|
|
|
|
|
|
|
Side oppSide = UnknownSide;
|
|
|
|
switch(aSide) {
|
|
|
|
case ChildSide: oppSide = ParentSide; break;
|
|
|
|
case ParentSide: oppSide = ChildSide; break;
|
|
|
|
case UnknownSide: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMonitor = new RefCountedMonitor();
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
mChannelState = ChannelOpening;
|
2017-08-03 12:21:44 +03:00
|
|
|
MOZ_ALWAYS_SUCCEEDS(aEventTarget->Dispatch(NewNonOwningRunnableMethod<MessageChannel*, Side>(
|
2017-06-12 22:34:10 +03:00
|
|
|
"ipc::MessageChannel::OnOpenAsSlave",
|
|
|
|
aTargetChan,
|
|
|
|
&MessageChannel::OnOpenAsSlave,
|
|
|
|
this,
|
2017-08-03 12:21:44 +03:00
|
|
|
oppSide)));
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
while (ChannelOpening == mChannelState)
|
|
|
|
mMonitor->Wait();
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(ChannelConnected == mChannelState, "not connected when awoken");
|
2013-09-28 05:42:08 +04:00
|
|
|
return (ChannelConnected == mChannelState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide)
|
|
|
|
{
|
|
|
|
// Invoked when the other side has begun the open.
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(ChannelClosed == mChannelState, "Not currently closed");
|
|
|
|
MOZ_ASSERT(ChannelOpening == aTargetChan->mChannelState,
|
|
|
|
"Target channel not in the process of opening");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
CommonThreadOpenInit(aTargetChan, aSide);
|
|
|
|
mMonitor = aTargetChan->mMonitor;
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(ChannelOpening == aTargetChan->mChannelState,
|
|
|
|
"Target channel not in the process of opening");
|
2013-09-28 05:42:08 +04:00
|
|
|
mChannelState = ChannelConnected;
|
|
|
|
aTargetChan->mChannelState = ChannelConnected;
|
|
|
|
aTargetChan->mMonitor->Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide)
|
|
|
|
{
|
|
|
|
mWorkerLoop = MessageLoop::current();
|
2017-05-26 02:51:31 +03:00
|
|
|
mWorkerThread = GetCurrentVirtualThread();
|
2017-03-21 00:15:44 +03:00
|
|
|
mWorkerLoop->AddDestructionObserver(this);
|
2017-05-10 22:52:20 +03:00
|
|
|
mListener->SetIsMainThreadProtocol();
|
2017-03-16 12:36:15 +03:00
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
mLink = new ThreadLink(this, aTargetChan);
|
|
|
|
mSide = aSide;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::Echo(Message* aMsg)
|
|
|
|
{
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<Message> msg(aMsg);
|
2013-09-28 05:42:08 +04:00
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
2013-11-15 00:24:18 +04:00
|
|
|
if (MSG_ROUTING_NONE == msg->routing_id()) {
|
|
|
|
ReportMessageRouteError("MessageChannel::Echo");
|
|
|
|
return false;
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
|
|
|
|
if (!Connected()) {
|
2017-09-21 22:52:37 +03:00
|
|
|
ReportConnectionError("MessageChannel", msg.get());
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
mLink->EchoMessage(msg.release());
|
2013-09-28 05:42:08 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::Send(Message* aMsg)
|
|
|
|
{
|
2016-05-17 01:09:51 +03:00
|
|
|
if (aMsg->size() >= kMinTelemetryMessageSize) {
|
2017-05-04 11:34:20 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE2, aMsg->size());
|
2016-03-31 01:25:54 +03:00
|
|
|
}
|
|
|
|
|
2017-03-08 02:02:39 +03:00
|
|
|
// If the message was created by the IPC bindings, the create time will be
|
2017-03-13 21:46:19 +03:00
|
|
|
// recorded. Use this information to report the IPC_WRITE_MAIN_THREAD_LATENCY_MS (time
|
2017-03-08 02:02:39 +03:00
|
|
|
// from message creation to it being sent).
|
2017-03-13 21:46:19 +03:00
|
|
|
if (NS_IsMainThread() && aMsg->create_time()) {
|
2017-03-08 02:02:39 +03:00
|
|
|
uint32_t latencyMs = round((mozilla::TimeStamp::Now() - aMsg->create_time()).ToMilliseconds());
|
|
|
|
if (latencyMs >= kMinTelemetryIPCWriteLatencyMs) {
|
2017-03-13 21:46:19 +03:00
|
|
|
mozilla::Telemetry::Accumulate(mozilla::Telemetry::IPC_WRITE_MAIN_THREAD_LATENCY_MS,
|
2017-03-08 02:02:39 +03:00
|
|
|
nsDependentCString(aMsg->name()),
|
|
|
|
latencyMs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 14:14:49 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!aMsg->is_sync());
|
2016-10-01 02:20:50 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aMsg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
|
2016-10-01 14:14:49 +03:00
|
|
|
|
2014-01-11 00:58:20 +04:00
|
|
|
CxxStackFrame frame(*this, OUT_MESSAGE, aMsg);
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<Message> msg(aMsg);
|
2013-09-28 05:42:08 +04:00
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
2013-11-15 00:24:18 +04:00
|
|
|
if (MSG_ROUTING_NONE == msg->routing_id()) {
|
|
|
|
ReportMessageRouteError("MessageChannel::Send");
|
|
|
|
return false;
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
if (!Connected()) {
|
2017-09-21 22:52:37 +03:00
|
|
|
ReportConnectionError("MessageChannel", msg.get());
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
2017-09-21 22:52:37 +03:00
|
|
|
SendMessageToLink(msg.release());
|
2013-09-28 05:42:08 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-21 23:40:18 +03:00
|
|
|
void
|
|
|
|
MessageChannel::SendMessageToLink(Message* aMsg)
|
|
|
|
{
|
|
|
|
if (mIsPostponingSends) {
|
|
|
|
UniquePtr<Message> msg(aMsg);
|
2018-05-30 22:15:35 +03:00
|
|
|
mPostponedSends.push_back(std::move(msg));
|
2017-06-21 23:40:18 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
mLink->SendMessage(aMsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::BeginPostponingSends()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!mIsPostponingSends);
|
|
|
|
mIsPostponingSends = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::StopPostponingSends()
|
|
|
|
{
|
|
|
|
// Note: this can be called from any thread.
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
|
|
|
|
MOZ_ASSERT(mIsPostponingSends);
|
|
|
|
|
|
|
|
for (UniquePtr<Message>& iter : mPostponedSends) {
|
|
|
|
mLink->SendMessage(iter.release());
|
|
|
|
}
|
|
|
|
|
|
|
|
// We unset this after SendMessage so we can make correct thread
|
|
|
|
// assertions in MessageLink.
|
|
|
|
mIsPostponingSends = false;
|
|
|
|
mPostponedSends.clear();
|
|
|
|
}
|
|
|
|
|
2017-11-16 23:12:06 +03:00
|
|
|
UniquePtr<MessageChannel::UntypedCallbackHolder>
|
|
|
|
MessageChannel::PopCallback(const Message& aMsg)
|
2017-03-16 12:36:15 +03:00
|
|
|
{
|
2017-11-16 23:12:06 +03:00
|
|
|
auto iter = mPendingResponses.find(aMsg.seqno());
|
|
|
|
if (iter != mPendingResponses.end()) {
|
2018-05-30 22:15:35 +03:00
|
|
|
UniquePtr<MessageChannel::UntypedCallbackHolder> ret = std::move(iter->second);
|
2017-11-16 23:12:06 +03:00
|
|
|
mPendingResponses.erase(iter);
|
|
|
|
gUnresolvedResponses--;
|
|
|
|
return ret;
|
2017-03-16 12:36:15 +03:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-05-17 11:59:48 +03:00
|
|
|
void
|
2017-11-16 23:12:06 +03:00
|
|
|
MessageChannel::RejectPendingResponsesForActor(ActorIdType aActorId)
|
2017-05-17 11:59:48 +03:00
|
|
|
{
|
2017-11-16 23:12:06 +03:00
|
|
|
auto itr = mPendingResponses.begin();
|
|
|
|
while (itr != mPendingResponses.end()) {
|
|
|
|
if (itr->second.get()->mActorId != aActorId) {
|
2017-05-17 11:59:48 +03:00
|
|
|
++itr;
|
|
|
|
continue;
|
|
|
|
}
|
2017-11-16 23:12:06 +03:00
|
|
|
itr->second.get()->Reject(ResponseRejectReason::ActorDestroyed);
|
2017-05-17 11:59:48 +03:00
|
|
|
// Take special care of advancing the iterator since we are
|
|
|
|
// removing it while iterating.
|
2017-11-16 23:12:06 +03:00
|
|
|
itr = mPendingResponses.erase(itr);
|
|
|
|
gUnresolvedResponses--;
|
2017-05-17 11:59:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 17:31:44 +03:00
|
|
|
class BuildIDsMatchMessage : public IPC::Message
|
2017-03-11 04:01:38 +03:00
|
|
|
{
|
|
|
|
public:
|
2018-05-08 17:31:44 +03:00
|
|
|
BuildIDsMatchMessage()
|
|
|
|
: IPC::Message(MSG_ROUTING_NONE, BUILD_IDS_MATCH_MESSAGE_TYPE)
|
2017-03-11 04:01:38 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
void Log(const std::string& aPrefix, FILE* aOutf) const
|
|
|
|
{
|
2018-05-08 17:31:44 +03:00
|
|
|
fputs("(special `Build IDs match' message)", aOutf);
|
2017-03-11 04:01:38 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-08 17:31:44 +03:00
|
|
|
// Send the parent a special async message to confirm when the parent and child
|
|
|
|
// are of the same buildID. Skips sending the message and returns false if the
|
|
|
|
// buildIDs don't match. This is a minor variation on
|
|
|
|
// MessageChannel::Send(Message* aMsg).
|
|
|
|
bool
|
|
|
|
MessageChannel::SendBuildIDsMatchMessage(const char* aParentBuildID)
|
2017-03-11 04:01:38 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
2018-05-08 17:31:44 +03:00
|
|
|
|
|
|
|
nsCString parentBuildID(aParentBuildID);
|
|
|
|
nsCString childBuildID(mozilla::PlatformBuildID());
|
|
|
|
|
|
|
|
if (parentBuildID != childBuildID) {
|
|
|
|
// The build IDs didn't match, usually because an update occurred in the
|
|
|
|
// background.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoPtr<BuildIDsMatchMessage> msg(new BuildIDsMatchMessage());
|
2017-03-11 04:01:38 +03:00
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(!msg->is_sync());
|
|
|
|
MOZ_RELEASE_ASSERT(msg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
|
|
|
|
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
// Don't check for MSG_ROUTING_NONE.
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
if (!Connected()) {
|
|
|
|
ReportConnectionError("MessageChannel", msg);
|
2018-05-08 17:31:44 +03:00
|
|
|
return false;
|
2017-03-11 04:01:38 +03:00
|
|
|
}
|
|
|
|
mLink->SendMessage(msg.forget());
|
2018-05-08 17:31:44 +03:00
|
|
|
return true;
|
2017-03-11 04:01:38 +03:00
|
|
|
}
|
|
|
|
|
2015-06-24 03:52:01 +03:00
|
|
|
class CancelMessage : public IPC::Message
|
|
|
|
{
|
|
|
|
public:
|
2016-01-23 04:45:43 +03:00
|
|
|
explicit CancelMessage(int transaction) :
|
2016-10-01 02:20:50 +03:00
|
|
|
IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE)
|
2015-06-24 03:52:01 +03:00
|
|
|
{
|
2016-01-23 04:45:43 +03:00
|
|
|
set_transaction_id(transaction);
|
2015-06-24 03:52:01 +03:00
|
|
|
}
|
|
|
|
static bool Read(const Message* msg) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void Log(const std::string& aPrefix, FILE* aOutf) const {
|
|
|
|
fputs("(special `Cancel' message)", aOutf);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
bool
|
|
|
|
MessageChannel::MaybeInterceptSpecialIOMessage(const Message& aMsg)
|
|
|
|
{
|
|
|
|
AssertLinkThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2015-06-19 21:32:35 +03:00
|
|
|
if (MSG_ROUTING_NONE == aMsg.routing_id()) {
|
|
|
|
if (GOODBYE_MESSAGE_TYPE == aMsg.type()) {
|
|
|
|
// :TODO: Sort out Close() on this side racing with Close() on the
|
|
|
|
// other side
|
|
|
|
mChannelState = ChannelClosing;
|
|
|
|
if (LoggingEnabled()) {
|
|
|
|
printf("NOTE: %s process received `Goodbye', closing down\n",
|
|
|
|
(mSide == ChildSide) ? "child" : "parent");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else if (CANCEL_MESSAGE_TYPE == aMsg.type()) {
|
2016-01-20 04:25:39 +03:00
|
|
|
IPC_LOG("Cancel from message");
|
2016-01-23 04:52:23 +03:00
|
|
|
CancelTransaction(aMsg.transaction_id());
|
|
|
|
NotifyWorkerThread();
|
|
|
|
return true;
|
2018-05-08 17:31:44 +03:00
|
|
|
} else if (BUILD_IDS_MATCH_MESSAGE_TYPE == aMsg.type()) {
|
|
|
|
IPC_LOG("Build IDs match message");
|
|
|
|
mBuildIDsConfirmedMatch = true;
|
2017-03-11 04:01:38 +03:00
|
|
|
return true;
|
2013-11-27 11:59:41 +04:00
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
/* static */ bool
|
|
|
|
MessageChannel::IsAlwaysDeferred(const Message& aMsg)
|
|
|
|
{
|
|
|
|
// If a message is not NESTED_INSIDE_CPOW and not sync, then we always defer
|
|
|
|
// it.
|
|
|
|
return aMsg.nested_level() != IPC::Message::NESTED_INSIDE_CPOW &&
|
|
|
|
!aMsg.is_sync();
|
|
|
|
}
|
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
bool
|
|
|
|
MessageChannel::ShouldDeferMessage(const Message& aMsg)
|
|
|
|
{
|
2016-10-01 02:20:50 +03:00
|
|
|
// Never defer messages that have the highest nested level, even async
|
2014-10-08 08:32:45 +04:00
|
|
|
// ones. This is safe because only the child can send these messages, so
|
|
|
|
// they can never nest.
|
2017-04-11 07:44:56 +03:00
|
|
|
if (aMsg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
|
|
|
|
MOZ_ASSERT(!IsAlwaysDeferred(aMsg));
|
2014-10-08 08:32:45 +04:00
|
|
|
return false;
|
2017-04-11 07:44:56 +03:00
|
|
|
}
|
2014-10-08 08:32:45 +04:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// Unless they're NESTED_INSIDE_CPOW, we always defer async messages.
|
|
|
|
// Note that we never send an async NESTED_INSIDE_SYNC message.
|
2014-10-08 08:32:45 +04:00
|
|
|
if (!aMsg.is_sync()) {
|
2016-10-01 02:20:50 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aMsg.nested_level() == IPC::Message::NOT_NESTED);
|
2017-04-11 07:44:56 +03:00
|
|
|
MOZ_ASSERT(IsAlwaysDeferred(aMsg));
|
2014-10-08 08:32:45 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
MOZ_ASSERT(!IsAlwaysDeferred(aMsg));
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
int msgNestedLevel = aMsg.nested_level();
|
|
|
|
int waitingNestedLevel = AwaitingSyncReplyNestedLevel();
|
2014-10-08 08:32:45 +04:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// Always defer if the nested level of the incoming message is less than the
|
|
|
|
// nested level of the message we're awaiting.
|
|
|
|
if (msgNestedLevel < waitingNestedLevel)
|
2014-10-08 08:32:45 +04:00
|
|
|
return true;
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// Never defer if the message has strictly greater nested level.
|
|
|
|
if (msgNestedLevel > waitingNestedLevel)
|
2014-10-08 08:32:45 +04:00
|
|
|
return false;
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// When both sides send sync messages of the same nested level, we resolve the
|
2014-10-08 08:32:45 +04:00
|
|
|
// race by dispatching in the child and deferring the incoming message in
|
|
|
|
// the parent. However, the parent still needs to dispatch nested sync
|
|
|
|
// messages.
|
|
|
|
//
|
|
|
|
// Deferring in the parent only sort of breaks message ordering. When the
|
|
|
|
// child's message comes in, we can pretend the child hasn't quite
|
|
|
|
// finished sending it yet. Since the message is sync, we know that the
|
|
|
|
// child hasn't moved on yet.
|
2016-10-01 02:20:50 +03:00
|
|
|
return mSide == ParentSide && aMsg.transaction_id() != CurrentNestedInsideSyncTransaction();
|
2014-10-08 08:32:45 +04:00
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
2016-03-01 02:43:35 +03:00
|
|
|
MessageChannel::OnMessageReceivedFromLink(Message&& aMsg)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
AssertLinkThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
if (MaybeInterceptSpecialIOMessage(aMsg))
|
|
|
|
return;
|
|
|
|
|
2018-04-23 21:13:37 +03:00
|
|
|
#ifdef EARLY_BETA_OR_EARLIER
|
2017-05-02 15:10:00 +03:00
|
|
|
mListener->OnChannelReceivedMessage(aMsg);
|
2018-04-23 21:13:37 +03:00
|
|
|
#endif
|
2017-05-02 15:10:00 +03:00
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
// Regardless of the Interrupt stack, if we're awaiting a sync reply,
|
2013-09-28 05:42:08 +04:00
|
|
|
// we know that it needs to be immediately handled to unblock us.
|
2014-12-19 04:35:44 +03:00
|
|
|
if (aMsg.is_sync() && aMsg.is_reply()) {
|
2016-01-20 04:23:28 +03:00
|
|
|
IPC_LOG("Received reply seqno=%d xid=%d", aMsg.seqno(), aMsg.transaction_id());
|
|
|
|
|
2014-12-19 04:35:44 +03:00
|
|
|
if (aMsg.seqno() == mTimedOutMessageSeqno) {
|
|
|
|
// Drop the message, but allow future sync messages to be sent.
|
2016-01-20 04:23:28 +03:00
|
|
|
IPC_LOG("Received reply to timedout message; igoring; xid=%d", mTimedOutMessageSeqno);
|
2016-01-23 05:02:27 +03:00
|
|
|
EndTimeout();
|
2014-12-19 04:35:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(AwaitingSyncReply());
|
|
|
|
MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
|
2014-12-19 04:35:44 +03:00
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
mTransactionStack->HandleReply(std::move(aMsg));
|
2013-09-28 05:42:08 +04:00
|
|
|
NotifyWorkerThread();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// Nested messages cannot be compressed.
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aMsg.compress_type() == IPC::Message::COMPRESSION_NONE ||
|
2016-10-01 02:20:50 +03:00
|
|
|
aMsg.nested_level() == IPC::Message::NOT_NESTED);
|
2015-05-06 02:20:42 +03:00
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
bool reuseTask = false;
|
2015-05-06 02:20:42 +03:00
|
|
|
if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) {
|
2016-10-15 21:47:14 +03:00
|
|
|
bool compress = (!mPending.isEmpty() &&
|
|
|
|
mPending.getLast()->Msg().type() == aMsg.type() &&
|
|
|
|
mPending.getLast()->Msg().routing_id() == aMsg.routing_id());
|
2015-05-06 02:20:42 +03:00
|
|
|
if (compress) {
|
|
|
|
// This message type has compression enabled, and the back of the
|
|
|
|
// queue was the same message type and routed to the same destination.
|
|
|
|
// Replace it with the newer message.
|
2016-10-15 21:47:14 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mPending.getLast()->Msg().compress_type() ==
|
|
|
|
IPC::Message::COMPRESSION_ENABLED);
|
2018-05-30 22:15:35 +03:00
|
|
|
mPending.getLast()->Msg() = std::move(aMsg);
|
2016-10-15 21:47:14 +03:00
|
|
|
|
|
|
|
reuseTask = true;
|
2015-05-06 02:20:42 +03:00
|
|
|
}
|
2016-10-15 21:47:14 +03:00
|
|
|
} else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL && !mPending.isEmpty()) {
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* p = mPending.getLast(); p; p = p->getPrevious()) {
|
2016-10-15 21:47:14 +03:00
|
|
|
if (p->Msg().type() == aMsg.type() &&
|
|
|
|
p->Msg().routing_id() == aMsg.routing_id())
|
|
|
|
{
|
|
|
|
// This message type has compression enabled, and the queue
|
|
|
|
// holds a message with the same message type and routed to the
|
|
|
|
// same destination. Erase it. Note that, since we always
|
|
|
|
// compress these redundancies, There Can Be Only One.
|
|
|
|
MOZ_RELEASE_ASSERT(p->Msg().compress_type() == IPC::Message::COMPRESSION_ALL);
|
2017-04-11 07:44:56 +03:00
|
|
|
MOZ_RELEASE_ASSERT(IsAlwaysDeferred(p->Msg()));
|
2016-10-15 21:47:14 +03:00
|
|
|
p->remove();
|
|
|
|
break;
|
|
|
|
}
|
2015-05-06 02:20:42 +03:00
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
bool alwaysDeferred = IsAlwaysDeferred(aMsg);
|
|
|
|
|
2016-01-23 05:04:08 +03:00
|
|
|
bool wakeUpSyncSend = AwaitingSyncReply() && !ShouldDeferMessage(aMsg);
|
|
|
|
|
2013-10-01 20:15:03 +04:00
|
|
|
bool shouldWakeUp = AwaitingInterruptReply() ||
|
2016-01-23 05:04:08 +03:00
|
|
|
wakeUpSyncSend ||
|
2014-12-30 02:12:47 +03:00
|
|
|
AwaitingIncomingMessage();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
// Although we usually don't need to post a message task if
|
2016-01-23 05:04:08 +03:00
|
|
|
// shouldWakeUp is true, it's easier to post anyway than to have to
|
|
|
|
// guarantee that every Send call processes everything it's supposed to
|
|
|
|
// before returning.
|
|
|
|
bool shouldPostTask = !shouldWakeUp || wakeUpSyncSend;
|
|
|
|
|
2016-01-20 04:23:28 +03:00
|
|
|
IPC_LOG("Receive on link thread; seqno=%d, xid=%d, shouldWakeUp=%d",
|
|
|
|
aMsg.seqno(), aMsg.transaction_id(), shouldWakeUp);
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
if (reuseTask) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
// There are three cases we're concerned about, relating to the state of the
|
2013-09-28 05:42:08 +04:00
|
|
|
// main thread:
|
|
|
|
//
|
2014-10-08 08:32:45 +04:00
|
|
|
// (1) We are waiting on a sync reply - main thread is blocked on the
|
2013-10-01 20:15:03 +04:00
|
|
|
// IPC monitor.
|
2016-10-01 02:20:50 +03:00
|
|
|
// - If the message is NESTED_INSIDE_SYNC, we wake up the main thread to
|
2014-10-08 08:32:45 +04:00
|
|
|
// deliver the message depending on ShouldDeferMessage. Otherwise, we
|
|
|
|
// leave it in the mPending queue, posting a task to the main event
|
|
|
|
// loop, where it will be processed once the synchronous reply has been
|
|
|
|
// received.
|
2013-09-28 05:42:08 +04:00
|
|
|
//
|
2013-10-01 20:15:03 +04:00
|
|
|
// (2) We are waiting on an Interrupt reply - main thread is blocked on the
|
|
|
|
// IPC monitor.
|
2013-09-28 05:42:08 +04:00
|
|
|
// - Always notify and wake up the main thread.
|
|
|
|
//
|
|
|
|
// (3) We are not waiting on a reply.
|
|
|
|
// - We post a task to the main event loop.
|
|
|
|
//
|
|
|
|
// Note that, we may notify the main thread even though the monitor is not
|
|
|
|
// blocked. This is okay, since we always check for pending events before
|
|
|
|
// blocking again.
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
aMsg.TaskTracerDispatch();
|
|
|
|
#endif
|
2018-05-30 22:15:35 +03:00
|
|
|
RefPtr<MessageTask> task = new MessageTask(this, std::move(aMsg));
|
2016-10-15 21:47:14 +03:00
|
|
|
mPending.insertBack(task);
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
if (!alwaysDeferred) {
|
|
|
|
mMaybeDeferredPendingCount++;
|
|
|
|
}
|
|
|
|
|
2013-10-01 20:15:03 +04:00
|
|
|
if (shouldWakeUp) {
|
2013-09-28 05:42:08 +04:00
|
|
|
NotifyWorkerThread();
|
2016-01-23 05:04:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (shouldPostTask) {
|
2016-10-15 21:47:14 +03:00
|
|
|
task->Post();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 18:22:32 +03:00
|
|
|
void
|
2017-04-27 19:44:57 +03:00
|
|
|
MessageChannel::PeekMessages(const std::function<bool(const Message& aMsg)>& aInvoke)
|
2016-03-17 00:15:38 +03:00
|
|
|
{
|
2016-10-15 21:47:14 +03:00
|
|
|
// FIXME: We shouldn't be holding the lock for aInvoke!
|
2016-03-17 00:15:38 +03:00
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* it : mPending) {
|
2016-10-15 21:47:14 +03:00
|
|
|
const Message &msg = it->Msg();
|
2016-04-13 04:51:34 +03:00
|
|
|
if (!aInvoke(msg)) {
|
2016-03-28 06:02:18 +03:00
|
|
|
break;
|
2016-03-14 18:22:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-12 06:32:47 +03:00
|
|
|
void
|
2016-02-24 02:36:06 +03:00
|
|
|
MessageChannel::ProcessPendingRequests(AutoEnterTransaction& aTransaction)
|
2015-03-12 06:32:47 +03:00
|
|
|
{
|
2016-10-15 21:47:14 +03:00
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
AssertMaybeDeferredCountCorrect();
|
|
|
|
if (mMaybeDeferredPendingCount == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-08 18:53:43 +03:00
|
|
|
IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d",
|
|
|
|
aTransaction.SequenceNumber(), aTransaction.TransactionID());
|
2016-01-20 04:34:31 +03:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// Loop until there aren't any more nested messages to process.
|
2015-03-12 06:32:47 +03:00
|
|
|
for (;;) {
|
2016-01-23 07:32:50 +03:00
|
|
|
// If we canceled during ProcessPendingRequest, then we need to leave
|
|
|
|
// immediately because the results of ShouldDeferMessage will be
|
|
|
|
// operating with weird state (as if no Send is in progress). That could
|
2016-10-01 02:20:50 +03:00
|
|
|
// cause even NOT_NESTED sync messages to be processed (but not
|
|
|
|
// NOT_NESTED async messages), which would break message ordering.
|
2016-02-24 02:36:06 +03:00
|
|
|
if (aTransaction.IsCanceled()) {
|
2016-01-23 07:32:50 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-12 06:32:47 +03:00
|
|
|
mozilla::Vector<Message> toProcess;
|
|
|
|
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* p = mPending.getFirst(); p; ) {
|
2016-10-15 21:47:14 +03:00
|
|
|
Message &msg = p->Msg();
|
2016-01-20 04:34:31 +03:00
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!aTransaction.IsCanceled(),
|
|
|
|
"Calling ShouldDeferMessage when cancelled");
|
2016-01-20 04:34:31 +03:00
|
|
|
bool defer = ShouldDeferMessage(msg);
|
|
|
|
|
|
|
|
// Only log the interesting messages.
|
2016-10-01 02:20:50 +03:00
|
|
|
if (msg.is_sync() || msg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
|
2016-01-20 04:34:31 +03:00
|
|
|
IPC_LOG("ShouldDeferMessage(seqno=%d) = %d", msg.seqno(), defer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!defer) {
|
2017-04-11 07:44:56 +03:00
|
|
|
MOZ_ASSERT(!IsAlwaysDeferred(msg));
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
if (!toProcess.append(std::move(msg)))
|
2016-01-14 17:19:24 +03:00
|
|
|
MOZ_CRASH();
|
2016-10-15 21:47:14 +03:00
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
mMaybeDeferredPendingCount--;
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
p = p->removeAndGetNext();
|
2015-03-12 06:32:47 +03:00
|
|
|
continue;
|
|
|
|
}
|
2016-10-15 21:47:14 +03:00
|
|
|
p = p->getNext();
|
2015-03-12 06:32:47 +03:00
|
|
|
}
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
if (toProcess.empty()) {
|
2015-03-12 06:32:47 +03:00
|
|
|
break;
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
2015-03-12 06:32:47 +03:00
|
|
|
|
|
|
|
// Processing these messages could result in more messages, so we
|
|
|
|
// loop around to check for more afterwards.
|
2016-01-20 04:34:31 +03:00
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
for (auto it = toProcess.begin(); it != toProcess.end(); it++) {
|
2018-05-30 22:15:35 +03:00
|
|
|
ProcessPendingRequest(std::move(*it));
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
2015-03-12 06:32:47 +03:00
|
|
|
}
|
2017-04-11 07:44:56 +03:00
|
|
|
|
|
|
|
AssertMaybeDeferredCountCorrect();
|
2015-03-12 06:32:47 +03:00
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
bool
|
|
|
|
MessageChannel::Send(Message* aMsg, Message* aReply)
|
|
|
|
{
|
2017-01-31 11:28:41 +03:00
|
|
|
mozilla::TimeStamp start = TimeStamp::Now();
|
2016-05-17 01:09:51 +03:00
|
|
|
if (aMsg->size() >= kMinTelemetryMessageSize) {
|
2017-05-04 11:34:20 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE2, aMsg->size());
|
2016-03-31 01:25:54 +03:00
|
|
|
}
|
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<Message> msg(aMsg);
|
2015-07-02 01:17:33 +03:00
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
// Sanity checks.
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
#ifdef OS_WIN
|
|
|
|
SyncStackFrame frame(this, false);
|
2015-07-21 10:21:51 +03:00
|
|
|
NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
2013-09-28 05:42:08 +04:00
|
|
|
#endif
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
AutoScopedLabel autolabel("sync message %s", aMsg->name());
|
|
|
|
#endif
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
CxxStackFrame f(*this, OUT_MESSAGE, msg.get());
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
|
2014-12-19 04:35:44 +03:00
|
|
|
if (mTimedOutMessageSeqno) {
|
|
|
|
// Don't bother sending another sync message if a previous one timed out
|
|
|
|
// and we haven't received a reply for it. Once the original timed-out
|
|
|
|
// message receives a reply, we'll be able to send more sync messages
|
|
|
|
// again.
|
2016-01-20 04:23:28 +03:00
|
|
|
IPC_LOG("Send() failed due to previous timeout");
|
2016-01-23 04:45:43 +03:00
|
|
|
mLastSendError = SyncSendError::PreviousTimeout;
|
2014-12-19 04:35:44 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
if (DispatchingSyncMessageNestedLevel() == IPC::Message::NOT_NESTED &&
|
|
|
|
msg->nested_level() > IPC::Message::NOT_NESTED)
|
2015-06-20 00:10:20 +03:00
|
|
|
{
|
|
|
|
// Don't allow sending CPOWs while we're dispatching a sync message.
|
|
|
|
// If you want to do that, use sendRpcMessage instead.
|
2016-10-01 02:20:50 +03:00
|
|
|
IPC_LOG("Nested level forbids send");
|
2016-01-23 04:45:43 +03:00
|
|
|
mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync;
|
2016-01-20 04:36:44 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
if (DispatchingSyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW ||
|
|
|
|
DispatchingAsyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW)
|
2016-01-20 04:36:44 +03:00
|
|
|
{
|
|
|
|
// Generally only the parent dispatches urgent messages. And the only
|
2016-10-01 02:20:50 +03:00
|
|
|
// sync messages it can send are NESTED_INSIDE_SYNC. Mainly we want to ensure
|
2016-01-20 04:36:44 +03:00
|
|
|
// here that we don't return false for non-CPOW messages.
|
2016-10-01 02:20:50 +03:00
|
|
|
MOZ_RELEASE_ASSERT(msg->nested_level() == IPC::Message::NESTED_INSIDE_SYNC);
|
2016-01-23 04:45:43 +03:00
|
|
|
IPC_LOG("Sending while dispatching urgent message");
|
|
|
|
mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent;
|
2015-06-20 00:10:20 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
if (msg->nested_level() < DispatchingSyncMessageNestedLevel() ||
|
|
|
|
msg->nested_level() < AwaitingSyncReplyNestedLevel())
|
2015-06-24 03:52:01 +03:00
|
|
|
{
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage());
|
2017-06-21 23:40:18 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mIsPostponingSends);
|
2016-01-20 04:36:44 +03:00
|
|
|
IPC_LOG("Cancel from Send");
|
2016-10-01 02:20:50 +03:00
|
|
|
CancelMessage *cancel = new CancelMessage(CurrentNestedInsideSyncTransaction());
|
|
|
|
CancelTransaction(CurrentNestedInsideSyncTransaction());
|
2016-01-23 04:45:43 +03:00
|
|
|
mLink->SendMessage(cancel);
|
2015-06-24 03:52:01 +03:00
|
|
|
}
|
|
|
|
|
2015-07-02 01:17:33 +03:00
|
|
|
IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here");
|
2014-10-08 10:03:57 +04:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
IPC_ASSERT(msg->nested_level() >= DispatchingSyncMessageNestedLevel(),
|
|
|
|
"can't send sync message of a lesser nested level than what's being dispatched");
|
|
|
|
IPC_ASSERT(AwaitingSyncReplyNestedLevel() <= msg->nested_level(),
|
|
|
|
"nested sync message sends must be of increasing nested level");
|
|
|
|
IPC_ASSERT(DispatchingSyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
|
2016-02-24 02:36:06 +03:00
|
|
|
"not allowed to send messages while dispatching urgent messages");
|
2015-07-14 00:34:42 +03:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
IPC_ASSERT(DispatchingAsyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
|
2014-12-19 04:35:48 +03:00
|
|
|
"not allowed to send messages while dispatching urgent messages");
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
if (!Connected()) {
|
2017-09-21 22:52:37 +03:00
|
|
|
ReportConnectionError("MessageChannel::SendAndWait", msg.get());
|
2016-01-23 04:45:43 +03:00
|
|
|
mLastSendError = SyncSendError::NotConnectedBeforeSend;
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg->set_seqno(NextSeqno());
|
|
|
|
|
2014-12-19 04:35:44 +03:00
|
|
|
int32_t seqno = msg->seqno();
|
2016-10-01 02:20:50 +03:00
|
|
|
int nestedLevel = msg->nested_level();
|
2016-02-05 03:09:11 +03:00
|
|
|
msgid_t replyType = msg->type() + 1;
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
AutoEnterTransaction *stackTop = mTransactionStack;
|
2014-12-19 04:34:25 +03:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
// If the most recent message on the stack is NESTED_INSIDE_SYNC, then our
|
2016-02-24 02:36:06 +03:00
|
|
|
// message should nest inside that and we use the same transaction
|
|
|
|
// ID. Otherwise we need a new transaction ID (so we use the seqno of the
|
|
|
|
// message we're sending).
|
2016-10-01 02:20:50 +03:00
|
|
|
bool nest = stackTop && stackTop->NestedLevel() == IPC::Message::NESTED_INSIDE_SYNC;
|
2016-02-24 02:36:06 +03:00
|
|
|
int32_t transaction = nest ? stackTop->TransactionID() : seqno;
|
2016-03-05 03:04:41 +03:00
|
|
|
msg->set_transaction_id(transaction);
|
2016-02-24 02:36:06 +03:00
|
|
|
|
2016-03-05 03:04:41 +03:00
|
|
|
bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg);
|
2016-10-01 02:20:50 +03:00
|
|
|
AutoEnterTransaction transact(this, seqno, transaction, nestedLevel);
|
2016-02-24 02:36:06 +03:00
|
|
|
|
|
|
|
IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction);
|
|
|
|
|
2016-05-03 06:37:40 +03:00
|
|
|
// msg will be destroyed soon, but name() is not owned by msg.
|
|
|
|
const char* msgName = msg->name();
|
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
SendMessageToLink(msg.release());
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
while (true) {
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!transact.IsCanceled());
|
|
|
|
ProcessPendingRequests(transact);
|
|
|
|
if (transact.IsComplete()) {
|
|
|
|
break;
|
2016-01-23 07:32:14 +03:00
|
|
|
}
|
2016-01-23 07:32:14 +03:00
|
|
|
if (!Connected()) {
|
|
|
|
ReportConnectionError("MessageChannel::Send");
|
|
|
|
mLastSendError = SyncSendError::DisconnectedDuringSend;
|
|
|
|
return false;
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!transact.IsComplete());
|
|
|
|
MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
|
2014-12-19 04:35:44 +03:00
|
|
|
|
2015-10-08 00:38:08 +03:00
|
|
|
bool maybeTimedOut = !WaitForSyncNotify(handleWindowsMessages);
|
2016-02-24 02:36:06 +03:00
|
|
|
|
2016-02-25 01:04:44 +03:00
|
|
|
if (mListener->NeedArtificialSleep()) {
|
|
|
|
MonitorAutoUnlock unlock(*mMonitor);
|
|
|
|
mListener->ArtificialSleep();
|
|
|
|
}
|
2014-10-08 08:32:45 +04:00
|
|
|
|
|
|
|
if (!Connected()) {
|
|
|
|
ReportConnectionError("MessageChannel::SendAndWait");
|
2016-01-23 04:45:43 +03:00
|
|
|
mLastSendError = SyncSendError::DisconnectedDuringSend;
|
2014-10-08 08:32:45 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
if (transact.IsCanceled()) {
|
|
|
|
break;
|
2015-06-19 21:32:35 +03:00
|
|
|
}
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
|
|
|
|
|
2014-12-19 04:35:44 +03:00
|
|
|
// We only time out a message if it initiated a new transaction (i.e.,
|
|
|
|
// if neither side has any other message Sends on the stack).
|
2016-02-24 02:36:06 +03:00
|
|
|
bool canTimeOut = transact.IsBottom();
|
2014-12-19 04:35:44 +03:00
|
|
|
if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) {
|
2016-01-23 07:32:50 +03:00
|
|
|
// Since ShouldContinueFromTimeout drops the lock, we need to
|
|
|
|
// re-check all our conditions here. We shouldn't time out if any of
|
|
|
|
// these things happen because there won't be a reply to the timed
|
|
|
|
// out message in these cases.
|
2016-02-24 02:36:06 +03:00
|
|
|
if (transact.IsComplete()) {
|
2015-03-31 19:28:04 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-01-23 04:45:43 +03:00
|
|
|
IPC_LOG("Timing out Send: xid=%d", transaction);
|
|
|
|
|
2014-12-19 04:35:44 +03:00
|
|
|
mTimedOutMessageSeqno = seqno;
|
2016-10-01 02:20:50 +03:00
|
|
|
mTimedOutMessageNestedLevel = nestedLevel;
|
2016-01-23 04:45:43 +03:00
|
|
|
mLastSendError = SyncSendError::TimedOut;
|
2014-10-08 08:32:45 +04:00
|
|
|
return false;
|
2014-12-19 04:35:44 +03:00
|
|
|
}
|
2016-02-24 02:36:06 +03:00
|
|
|
|
|
|
|
if (transact.IsCanceled()) {
|
|
|
|
break;
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
if (transact.IsCanceled()) {
|
|
|
|
IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction);
|
|
|
|
mLastSendError = SyncSendError::CancelledAfterSend;
|
|
|
|
return false;
|
|
|
|
}
|
2015-03-31 19:28:04 +03:00
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
if (transact.IsError()) {
|
|
|
|
IPC_LOG("Error: seqno=%d, xid=%d", seqno, transaction);
|
|
|
|
mLastSendError = SyncSendError::ReplyError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-31 11:28:41 +03:00
|
|
|
uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
|
|
|
|
IPC_LOG("Got reply: seqno=%d, xid=%d, msgName=%s, latency=%ums",
|
|
|
|
seqno, transaction, msgName, latencyMs);
|
2016-02-24 02:36:06 +03:00
|
|
|
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<Message> reply = transact.GetReply();
|
2016-02-24 02:36:06 +03:00
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(reply);
|
|
|
|
MOZ_RELEASE_ASSERT(reply->is_reply(), "expected reply");
|
|
|
|
MOZ_RELEASE_ASSERT(!reply->is_reply_error());
|
|
|
|
MOZ_RELEASE_ASSERT(reply->seqno() == seqno);
|
|
|
|
MOZ_RELEASE_ASSERT(reply->type() == replyType, "wrong reply type");
|
|
|
|
MOZ_RELEASE_ASSERT(reply->is_sync());
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
*aReply = std::move(*reply);
|
2016-05-17 01:09:51 +03:00
|
|
|
if (aReply->size() >= kMinTelemetryMessageSize) {
|
2016-04-26 23:50:56 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::IPC_REPLY_SIZE,
|
2016-05-17 01:09:51 +03:00
|
|
|
nsDependentCString(msgName), aReply->size());
|
2016-04-26 23:50:56 +03:00
|
|
|
}
|
2017-01-31 11:28:41 +03:00
|
|
|
|
2017-03-09 01:53:50 +03:00
|
|
|
// NOTE: Only collect IPC_SYNC_MAIN_LATENCY_MS on the main thread (bug 1343729)
|
2017-03-07 22:16:53 +03:00
|
|
|
if (NS_IsMainThread() && latencyMs >= kMinTelemetrySyncIPCLatencyMs) {
|
2017-03-09 01:53:50 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::IPC_SYNC_MAIN_LATENCY_MS,
|
2017-01-31 11:28:41 +03:00
|
|
|
nsDependentCString(msgName), latencyMs);
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::Call(Message* aMsg, Message* aReply)
|
|
|
|
{
|
2017-09-21 22:52:37 +03:00
|
|
|
UniquePtr<Message> msg(aMsg);
|
2013-09-28 05:42:08 +04:00
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
#ifdef OS_WIN
|
|
|
|
SyncStackFrame frame(this, true);
|
|
|
|
#endif
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
AutoScopedLabel autolabel("sync message %s", aMsg->name());
|
|
|
|
#endif
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
// This must come before MonitorAutoLock, as its destructor acquires the
|
|
|
|
// monitor lock.
|
2017-09-21 22:52:37 +03:00
|
|
|
CxxStackFrame cxxframe(*this, OUT_MESSAGE, msg.get());
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
if (!Connected()) {
|
2017-09-21 22:52:37 +03:00
|
|
|
ReportConnectionError("MessageChannel::Call", msg.get());
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanity checks.
|
2014-10-08 08:32:45 +04:00
|
|
|
IPC_ASSERT(!AwaitingSyncReply(),
|
|
|
|
"cannot issue Interrupt call while blocked on sync request");
|
|
|
|
IPC_ASSERT(!DispatchingSyncMessage(),
|
2013-09-28 05:42:08 +04:00
|
|
|
"violation of sync handler invariant");
|
2015-10-26 22:38:19 +03:00
|
|
|
IPC_ASSERT(msg->is_interrupt(), "can only Call() Interrupt messages here");
|
2017-06-21 23:40:18 +03:00
|
|
|
IPC_ASSERT(!mIsPostponingSends, "not postponing sends");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
msg->set_seqno(NextSeqno());
|
2013-10-01 04:27:45 +04:00
|
|
|
msg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess);
|
|
|
|
msg->set_interrupt_local_stack_depth(1 + InterruptStackDepth());
|
2016-04-28 02:21:49 +03:00
|
|
|
mInterruptStack.push(MessageInfo(*msg));
|
2017-09-21 22:52:37 +03:00
|
|
|
mLink->SendMessage(msg.release());
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
// if a handler invoked by *Dispatch*() spun a nested event
|
|
|
|
// loop, and the connection was broken during that loop, we
|
|
|
|
// might have already processed the OnError event. if so,
|
|
|
|
// trying another loop iteration will be futile because
|
|
|
|
// channel state will have been cleared
|
|
|
|
if (!Connected()) {
|
2014-10-08 08:32:45 +04:00
|
|
|
ReportConnectionError("MessageChannel::Call");
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-21 10:21:51 +03:00
|
|
|
#ifdef OS_WIN
|
2015-08-27 00:57:29 +03:00
|
|
|
// We need to limit the scoped of neuteredRgn to this spot in the code.
|
|
|
|
// Window neutering can't be enabled during some plugin calls because
|
|
|
|
// we then risk the neutered window procedure being subclassed by a
|
|
|
|
// plugin.
|
|
|
|
{
|
|
|
|
NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
|
|
|
/* We should pump messages at this point to ensure that the IPC peer
|
|
|
|
does not become deadlocked on a pending inter-thread SendMessage() */
|
|
|
|
neuteredRgn.PumpOnce();
|
|
|
|
}
|
2015-07-21 10:21:51 +03:00
|
|
|
#endif
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
// Now might be the time to process a message deferred because of race
|
|
|
|
// resolution.
|
|
|
|
MaybeUndeferIncall();
|
|
|
|
|
|
|
|
// Wait for an event to occur.
|
2013-10-01 04:27:45 +04:00
|
|
|
while (!InterruptEventOccurred()) {
|
|
|
|
bool maybeTimedOut = !WaitForInterruptNotify();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
// We might have received a "subtly deferred" message in a nested
|
|
|
|
// loop that it's now time to process.
|
2013-10-01 04:27:45 +04:00
|
|
|
if (InterruptEventOccurred() ||
|
2013-09-28 05:42:08 +04:00
|
|
|
(!maybeTimedOut && (!mDeferred.empty() || !mOutOfTurnReplies.empty())))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maybeTimedOut && !ShouldContinueFromTimeout())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Message recvd;
|
|
|
|
MessageMap::iterator it;
|
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
|
|
|
|
!= mOutOfTurnReplies.end())
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2018-05-30 22:15:35 +03:00
|
|
|
recvd = std::move(it->second);
|
2013-09-28 05:42:08 +04:00
|
|
|
mOutOfTurnReplies.erase(it);
|
2016-10-15 21:47:14 +03:00
|
|
|
} else if (!mPending.isEmpty()) {
|
|
|
|
RefPtr<MessageTask> task = mPending.popFirst();
|
2018-05-30 22:15:35 +03:00
|
|
|
recvd = std::move(task->Msg());
|
2017-04-11 07:44:56 +03:00
|
|
|
if (!IsAlwaysDeferred(recvd)) {
|
|
|
|
mMaybeDeferredPendingCount--;
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
} else {
|
|
|
|
// because of subtleties with nested event loops, it's possible
|
|
|
|
// that we got here and nothing happened. or, we might have a
|
|
|
|
// deferred in-call that needs to be processed. either way, we
|
|
|
|
// won't break the inner while loop again until something new
|
|
|
|
// happens.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
// If the message is not Interrupt, we can dispatch it as normal.
|
|
|
|
if (!recvd.is_interrupt()) {
|
2018-05-30 22:15:35 +03:00
|
|
|
DispatchMessage(std::move(recvd));
|
2013-09-28 05:42:08 +04:00
|
|
|
if (!Connected()) {
|
|
|
|
ReportConnectionError("MessageChannel::DispatchMessage");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
// If the message is an Interrupt reply, either process it as a reply to our
|
2013-09-28 05:42:08 +04:00
|
|
|
// call, or add it to the list of out-of-turn replies we've received.
|
|
|
|
if (recvd.is_reply()) {
|
2013-10-01 04:27:45 +04:00
|
|
|
IPC_ASSERT(!mInterruptStack.empty(), "invalid Interrupt stack");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
// If this is not a reply the call we've initiated, add it to our
|
|
|
|
// out-of-turn replies and keep polling for events.
|
|
|
|
{
|
2016-04-28 02:21:49 +03:00
|
|
|
const MessageInfo &outcall = mInterruptStack.top();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
// Note, In the parent, sequence numbers increase from 0, and
|
|
|
|
// in the child, they decrease from 0.
|
|
|
|
if ((mSide == ChildSide && recvd.seqno() > outcall.seqno()) ||
|
|
|
|
(mSide != ChildSide && recvd.seqno() < outcall.seqno()))
|
|
|
|
{
|
2018-05-30 22:15:35 +03:00
|
|
|
mOutOfTurnReplies[recvd.seqno()] = std::move(recvd);
|
2013-09-28 05:42:08 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC_ASSERT(recvd.is_reply_error() ||
|
|
|
|
(recvd.type() == (outcall.type() + 1) &&
|
|
|
|
recvd.seqno() == outcall.seqno()),
|
|
|
|
"somebody's misbehavin'", true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We received a reply to our most recent outstanding call. Pop
|
|
|
|
// this frame and return the reply.
|
2013-10-01 04:27:45 +04:00
|
|
|
mInterruptStack.pop();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2014-11-01 14:00:54 +03:00
|
|
|
bool is_reply_error = recvd.is_reply_error();
|
|
|
|
if (!is_reply_error) {
|
2018-05-30 22:15:35 +03:00
|
|
|
*aReply = std::move(recvd);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we have no more pending out calls waiting on replies, then
|
|
|
|
// the reply queue should be empty.
|
2013-10-01 04:27:45 +04:00
|
|
|
IPC_ASSERT(!mInterruptStack.empty() || mOutOfTurnReplies.empty(),
|
2013-09-28 05:42:08 +04:00
|
|
|
"still have pending replies with no pending out-calls",
|
|
|
|
true);
|
|
|
|
|
2014-11-01 14:00:54 +03:00
|
|
|
return !is_reply_error;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
// Dispatch an Interrupt in-call. Snapshot the current stack depth while we
|
2013-09-28 05:42:08 +04:00
|
|
|
// own the monitor.
|
2013-10-01 04:27:45 +04:00
|
|
|
size_t stackDepth = InterruptStackDepth();
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
Message::AutoTaskTracerRun tasktracerRun(recvd);
|
|
|
|
#endif
|
2013-09-28 05:42:08 +04:00
|
|
|
MonitorAutoUnlock unlock(*mMonitor);
|
|
|
|
|
|
|
|
CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
|
2018-05-30 22:15:35 +03:00
|
|
|
DispatchInterruptMessage(std::move(recvd), stackDepth);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
if (!Connected()) {
|
2013-10-01 04:27:45 +04:00
|
|
|
ReportConnectionError("MessageChannel::DispatchInterruptMessage");
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-30 02:12:47 +03:00
|
|
|
bool
|
|
|
|
MessageChannel::WaitForIncomingMessage()
|
|
|
|
{
|
|
|
|
#ifdef OS_WIN
|
|
|
|
SyncStackFrame frame(this, true);
|
2015-07-21 10:21:51 +03:00
|
|
|
NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
2014-12-30 02:12:47 +03:00
|
|
|
#endif
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
AutoEnterWaitForIncoming waitingForIncoming(*this);
|
|
|
|
if (mChannelState != ChannelConnected) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!HasPendingEvents()) {
|
|
|
|
return WaitForInterruptNotify();
|
2014-12-30 02:12:47 +03:00
|
|
|
}
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mPending.isEmpty());
|
|
|
|
RefPtr<MessageTask> task = mPending.getFirst();
|
|
|
|
RunMessage(*task);
|
|
|
|
return true;
|
2014-12-30 02:12:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::HasPendingEvents()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
2016-10-15 21:47:14 +03:00
|
|
|
return Connected() && !mPending.isEmpty();
|
2014-12-30 02:12:47 +03:00
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
bool
|
2013-10-01 04:27:45 +04:00
|
|
|
MessageChannel::InterruptEventOccurred()
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
2013-10-01 04:27:45 +04:00
|
|
|
IPC_ASSERT(InterruptStackDepth() > 0, "not in wait loop");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
return (!Connected() ||
|
2016-10-15 21:47:14 +03:00
|
|
|
!mPending.isEmpty() ||
|
2013-09-28 05:42:08 +04:00
|
|
|
(!mOutOfTurnReplies.empty() &&
|
2013-10-01 04:27:45 +04:00
|
|
|
mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
|
2013-09-28 05:42:08 +04:00
|
|
|
mOutOfTurnReplies.end()));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2016-05-17 00:02:43 +03:00
|
|
|
MessageChannel::ProcessPendingRequest(Message &&aUrgent)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
2013-10-01 20:15:03 +04:00
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2016-01-20 04:23:28 +03:00
|
|
|
IPC_LOG("Process pending: seqno=%d, xid=%d", aUrgent.seqno(), aUrgent.transaction_id());
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
DispatchMessage(std::move(aUrgent));
|
2013-10-01 20:15:03 +04:00
|
|
|
if (!Connected()) {
|
2014-10-08 08:32:45 +04:00
|
|
|
ReportConnectionError("MessageChannel::ProcessPendingRequest");
|
2013-10-01 20:15:03 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2016-10-15 21:47:14 +03:00
|
|
|
MessageChannel::ShouldRunMessage(const Message& aMsg)
|
2013-10-01 20:15:03 +04:00
|
|
|
{
|
2016-10-15 21:47:14 +03:00
|
|
|
if (!mTimedOutMessageSeqno) {
|
|
|
|
return true;
|
2013-10-01 20:15:03 +04:00
|
|
|
}
|
|
|
|
|
2016-01-23 05:02:27 +03:00
|
|
|
// If we've timed out a message and we're awaiting the reply to the timed
|
|
|
|
// out message, we have to be careful what messages we process. Here's what
|
|
|
|
// can go wrong:
|
2016-10-01 02:20:50 +03:00
|
|
|
// 1. child sends a NOT_NESTED sync message S
|
|
|
|
// 2. parent sends a NESTED_INSIDE_SYNC sync message H at the same time
|
2016-01-23 05:02:27 +03:00
|
|
|
// 3. parent times out H
|
2016-10-01 02:20:50 +03:00
|
|
|
// 4. child starts processing H and sends a NESTED_INSIDE_SYNC message H' nested
|
2016-01-23 05:02:27 +03:00
|
|
|
// within the same transaction
|
|
|
|
// 5. parent dispatches S and sends reply
|
|
|
|
// 6. child asserts because it instead expected a reply to H'.
|
|
|
|
//
|
|
|
|
// To solve this, we refuse to process S in the parent until we get a reply
|
|
|
|
// to H. More generally, let the timed out message be M. We don't process a
|
|
|
|
// message unless the child would need the response to that message in order
|
2016-10-01 02:20:50 +03:00
|
|
|
// to process M. Those messages are the ones that have a higher nested level
|
2016-01-23 05:02:27 +03:00
|
|
|
// than M or that are part of the same transaction as M.
|
2016-10-15 21:47:14 +03:00
|
|
|
if (aMsg.nested_level() < mTimedOutMessageNestedLevel ||
|
|
|
|
(aMsg.nested_level() == mTimedOutMessageNestedLevel
|
|
|
|
&& aMsg.transaction_id() != mTimedOutMessageSeqno))
|
|
|
|
{
|
2016-01-23 05:02:27 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-10-01 20:15:03 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
void
|
|
|
|
MessageChannel::RunMessage(MessageTask& aTask)
|
2013-10-01 20:15:03 +04:00
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
2016-10-15 21:47:14 +03:00
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
Message& msg = aTask.Msg();
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
if (!Connected()) {
|
|
|
|
ReportConnectionError("RunMessage");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that we're going to run the first message that's valid to run.
|
2017-09-02 02:31:51 +03:00
|
|
|
#if 0
|
2016-10-15 21:47:14 +03:00
|
|
|
#ifdef DEBUG
|
2017-09-02 02:31:51 +03:00
|
|
|
nsCOMPtr<nsIEventTarget> messageTarget =
|
|
|
|
mListener->GetMessageEventTarget(msg);
|
|
|
|
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* task : mPending) {
|
2016-10-15 21:47:14 +03:00
|
|
|
if (task == &aTask) {
|
|
|
|
break;
|
|
|
|
}
|
2016-11-08 15:05:45 +03:00
|
|
|
|
2017-09-02 02:31:51 +03:00
|
|
|
nsCOMPtr<nsIEventTarget> taskTarget =
|
|
|
|
mListener->GetMessageEventTarget(task->Msg());
|
|
|
|
|
2016-11-08 15:05:45 +03:00
|
|
|
MOZ_ASSERT(!ShouldRunMessage(task->Msg()) ||
|
2017-09-02 02:31:51 +03:00
|
|
|
taskTarget != messageTarget ||
|
2016-11-08 15:05:45 +03:00
|
|
|
aTask.Msg().priority() != task->Msg().priority());
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
}
|
2017-09-02 02:31:51 +03:00
|
|
|
#endif
|
2016-10-15 21:47:14 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!mDeferred.empty()) {
|
|
|
|
MaybeUndeferIncall();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ShouldRunMessage(msg)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(aTask.isInList());
|
|
|
|
aTask.remove();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
if (!IsAlwaysDeferred(msg)) {
|
|
|
|
mMaybeDeferredPendingCount--;
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
if (IsOnCxxStack() && msg.is_interrupt() && msg.is_reply()) {
|
2013-09-28 05:42:08 +04:00
|
|
|
// We probably just received a reply in a nested loop for an
|
2013-10-01 04:27:45 +04:00
|
|
|
// Interrupt call sent before entering that loop.
|
2018-05-30 22:15:35 +03:00
|
|
|
mOutOfTurnReplies[msg.seqno()] = std::move(msg);
|
2016-10-15 21:47:14 +03:00
|
|
|
return;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
DispatchMessage(std::move(msg));
|
2016-10-15 21:47:14 +03:00
|
|
|
}
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2016-11-08 15:05:45 +03:00
|
|
|
NS_IMPL_ISUPPORTS_INHERITED(MessageChannel::MessageTask, CancelableRunnable, nsIRunnablePriority)
|
|
|
|
|
2017-01-18 03:50:34 +03:00
|
|
|
MessageChannel::MessageTask::MessageTask(MessageChannel* aChannel, Message&& aMessage)
|
2017-09-14 11:08:57 +03:00
|
|
|
: CancelableRunnable(aMessage.name())
|
2017-01-18 03:50:34 +03:00
|
|
|
, mChannel(aChannel)
|
2018-05-30 22:15:35 +03:00
|
|
|
, mMessage(std::move(aMessage))
|
2017-01-18 03:50:34 +03:00
|
|
|
, mScheduled(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
nsresult
|
|
|
|
MessageChannel::MessageTask::Run()
|
|
|
|
{
|
|
|
|
if (!mChannel) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChannel->AssertWorkerThread();
|
|
|
|
mChannel->mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mChannel->mMonitor);
|
|
|
|
|
|
|
|
// In case we choose not to run this message, we may need to be able to Post
|
|
|
|
// it again.
|
|
|
|
mScheduled = false;
|
|
|
|
|
|
|
|
if (!isInList()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChannel->RunMessage(*this);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warning: This method removes the receiver from whatever list it might be in.
|
|
|
|
nsresult
|
|
|
|
MessageChannel::MessageTask::Cancel()
|
|
|
|
{
|
|
|
|
if (!mChannel) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChannel->AssertWorkerThread();
|
|
|
|
mChannel->mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mChannel->mMonitor);
|
|
|
|
|
|
|
|
if (!isInList()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
remove();
|
|
|
|
|
2017-04-11 07:44:56 +03:00
|
|
|
if (!IsAlwaysDeferred(Msg())) {
|
|
|
|
mChannel->mMaybeDeferredPendingCount--;
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::MessageTask::Post()
|
|
|
|
{
|
|
|
|
MOZ_RELEASE_ASSERT(!mScheduled);
|
|
|
|
MOZ_RELEASE_ASSERT(isInList());
|
|
|
|
|
|
|
|
mScheduled = true;
|
|
|
|
|
|
|
|
RefPtr<MessageTask> self = this;
|
2016-10-29 06:46:59 +03:00
|
|
|
nsCOMPtr<nsIEventTarget> eventTarget =
|
|
|
|
mChannel->mListener->GetMessageEventTarget(mMessage);
|
|
|
|
|
|
|
|
if (eventTarget) {
|
|
|
|
eventTarget->Dispatch(self.forget(), NS_DISPATCH_NORMAL);
|
2017-09-23 02:31:07 +03:00
|
|
|
} else if (mChannel->mWorkerLoop) {
|
2016-10-29 06:46:59 +03:00
|
|
|
mChannel->mWorkerLoop->PostTask(self.forget());
|
|
|
|
}
|
2016-10-15 21:47:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::MessageTask::Clear()
|
|
|
|
{
|
|
|
|
mChannel->AssertWorkerThread();
|
|
|
|
|
|
|
|
mChannel = nullptr;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2016-11-08 15:05:45 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MessageChannel::MessageTask::GetPriority(uint32_t* aPriority)
|
|
|
|
{
|
2017-03-21 10:44:12 +03:00
|
|
|
switch (mMessage.priority()) {
|
|
|
|
case Message::NORMAL_PRIORITY:
|
|
|
|
*aPriority = PRIORITY_NORMAL;
|
|
|
|
break;
|
|
|
|
case Message::INPUT_PRIORITY:
|
|
|
|
*aPriority = PRIORITY_INPUT;
|
|
|
|
break;
|
|
|
|
case Message::HIGH_PRIORITY:
|
|
|
|
*aPriority = PRIORITY_HIGH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT(false);
|
|
|
|
break;
|
|
|
|
}
|
2016-11-08 15:05:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-07-20 02:23:01 +03:00
|
|
|
bool
|
2017-09-13 06:59:35 +03:00
|
|
|
MessageChannel::MessageTask::GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups)
|
2017-07-20 02:23:01 +03:00
|
|
|
{
|
|
|
|
if (!mChannel) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChannel->AssertWorkerThread();
|
|
|
|
return mChannel->mListener->GetMessageSchedulerGroups(mMessage, aGroups);
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
2016-05-17 00:02:43 +03:00
|
|
|
MessageChannel::DispatchMessage(Message &&aMsg)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2016-10-15 21:47:14 +03:00
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2014-12-06 20:51:14 +03:00
|
|
|
Maybe<AutoNoJSAPI> nojsapi;
|
|
|
|
if (ScriptSettingsInitialized() && NS_IsMainThread())
|
|
|
|
nojsapi.emplace();
|
2015-07-01 00:48:29 +03:00
|
|
|
|
|
|
|
nsAutoPtr<Message> reply;
|
|
|
|
|
2016-01-20 04:23:28 +03:00
|
|
|
IPC_LOG("DispatchMessage: seqno=%d, xid=%d", aMsg.seqno(), aMsg.transaction_id());
|
|
|
|
|
2015-07-01 00:48:29 +03:00
|
|
|
{
|
|
|
|
AutoEnterTransaction transaction(this, aMsg);
|
|
|
|
|
2015-06-19 21:32:35 +03:00
|
|
|
int id = aMsg.transaction_id();
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!aMsg.is_sync() || id == transaction.TransactionID());
|
2015-06-19 21:32:35 +03:00
|
|
|
|
|
|
|
{
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
Message::AutoTaskTracerRun tasktracerRun(aMsg);
|
|
|
|
#endif
|
2015-06-19 21:32:35 +03:00
|
|
|
MonitorAutoUnlock unlock(*mMonitor);
|
|
|
|
CxxStackFrame frame(*this, IN_MESSAGE, &aMsg);
|
|
|
|
|
2016-02-25 01:04:44 +03:00
|
|
|
mListener->ArtificialSleep();
|
|
|
|
|
2015-06-19 21:32:35 +03:00
|
|
|
if (aMsg.is_sync())
|
|
|
|
DispatchSyncMessage(aMsg, *getter_Transfers(reply));
|
|
|
|
else if (aMsg.is_interrupt())
|
2018-05-30 22:15:35 +03:00
|
|
|
DispatchInterruptMessage(std::move(aMsg), 0);
|
2015-06-19 21:32:35 +03:00
|
|
|
else
|
|
|
|
DispatchAsyncMessage(aMsg);
|
2016-02-25 01:04:44 +03:00
|
|
|
|
|
|
|
mListener->ArtificialSleep();
|
2015-06-19 21:32:35 +03:00
|
|
|
}
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
if (reply && transaction.IsCanceled()) {
|
2015-06-19 21:32:35 +03:00
|
|
|
// The transaction has been canceled. Don't send a reply.
|
2016-02-25 01:04:44 +03:00
|
|
|
IPC_LOG("Nulling out reply due to cancellation, seqno=%d, xid=%d", aMsg.seqno(), id);
|
2015-06-19 21:32:35 +03:00
|
|
|
reply = nullptr;
|
|
|
|
}
|
2015-07-01 00:48:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (reply && ChannelConnected == mChannelState) {
|
2016-02-25 01:04:44 +03:00
|
|
|
IPC_LOG("Sending reply seqno=%d, xid=%d", aMsg.seqno(), aMsg.transaction_id());
|
2015-07-01 00:48:29 +03:00
|
|
|
mLink->SendMessage(reply.forget());
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-07-01 00:48:29 +03:00
|
|
|
MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
|
2017-05-17 22:38:59 +03:00
|
|
|
mozilla::TimeStamp start = TimeStamp::Now();
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
int nestedLevel = aMsg.nested_level();
|
2015-10-07 21:13:08 +03:00
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
MOZ_RELEASE_ASSERT(nestedLevel == IPC::Message::NOT_NESTED || NS_IsMainThread());
|
2017-01-09 20:46:00 +03:00
|
|
|
#ifdef MOZ_TASK_TRACER
|
|
|
|
AutoScopedLabel autolabel("sync message %s", aMsg.name());
|
|
|
|
#endif
|
2013-12-15 03:50:22 +04:00
|
|
|
|
2015-06-24 03:52:01 +03:00
|
|
|
MessageChannel* dummy;
|
2016-02-02 04:24:39 +03:00
|
|
|
MessageChannel*& blockingVar = mSide == ChildSide && NS_IsMainThread() ? gParentProcessBlocker : dummy;
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
Result rv;
|
2016-01-26 03:57:25 +03:00
|
|
|
{
|
2015-06-24 03:52:01 +03:00
|
|
|
AutoSetValue<MessageChannel*> blocked(blockingVar, this);
|
2015-07-01 00:48:29 +03:00
|
|
|
rv = mListener->OnMessageReceived(aMsg, aReply);
|
2014-10-08 08:32:45 +04:00
|
|
|
}
|
2013-10-01 20:15:03 +04:00
|
|
|
|
2017-05-17 22:38:59 +03:00
|
|
|
uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
|
|
|
|
if (latencyMs >= kMinTelemetrySyncIPCLatencyMs) {
|
|
|
|
Telemetry::Accumulate(Telemetry::IPC_SYNC_RECEIVE_MS,
|
|
|
|
nsDependentCString(aMsg.name()),
|
|
|
|
latencyMs);
|
|
|
|
}
|
|
|
|
|
2014-10-08 08:32:45 +04:00
|
|
|
if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
|
Bug 1397823 - part 3 - do a better job setting IPC::Message flags; r=kanru
The current IPC::Message constructor takes a large number of arguments,
three of which--the nesting level, the priority, and the
compression--are almost always constant by virtue of the vast majority
of Message construction being done by auto-generated IPDL code. But
then we take these constant values into the Message constructor, we
check them for various values, and then based on those values, we
perform a bunch of bitfield operations to store flags based on those
values. This is wasted work.
Furthermore, for replies to IPDL messages, we'll construct a Message
object, and then call mutating setters on the Message object that will
perform even more bitfield manipulations. Again, these operations are
performing tasks at runtime that are the same every single time, and use
information we already have at compile time.
The impact of these extra operations is not large, maybe 15-30K of extra
code, depending on platform. Nonetheless, we can easily make them go
away, and make everything cleaner to boot.
This patch adds a HeaderFlags class that encapsulates all the knowledge
about the various kinds of flags Message needs to know about. We can
construct HeaderFlags objects with strongly-typed enum arguments for the
various kinds of flags, and the compiler can take care of folding all of
those flags together into a constant when possible (and it is possible
for all the IPDL-generated code that instantiates Messages). The upshot
is that we do no unnecessary work in the Message constructor itself. We
can also remove various mutating operations on Message, as those
operations were only there to support post-constructor flag twiddling,
which is no longer necessary.
2017-09-15 15:06:11 +03:00
|
|
|
aReply = Message::ForSyncDispatchError(aMsg.nested_level());
|
2015-07-03 08:08:54 +03:00
|
|
|
}
|
2015-07-01 00:48:29 +03:00
|
|
|
aReply->set_seqno(aMsg.seqno());
|
|
|
|
aReply->set_transaction_id(aMsg.transaction_id());
|
2013-10-01 20:15:03 +04:00
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
|
|
|
MessageChannel::DispatchAsyncMessage(const Message& aMsg)
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync());
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
if (aMsg.routing_id() == MSG_ROUTING_NONE) {
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("unhandled special message!");
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2014-12-19 04:35:48 +03:00
|
|
|
Result rv;
|
|
|
|
{
|
2016-10-01 02:20:50 +03:00
|
|
|
int nestedLevel = aMsg.nested_level();
|
2014-12-19 04:35:48 +03:00
|
|
|
AutoSetValue<bool> async(mDispatchingAsyncMessage, true);
|
2016-10-01 02:20:50 +03:00
|
|
|
AutoSetValue<int> nestedLevelSet(mDispatchingAsyncMessageNestedLevel, nestedLevel);
|
2014-12-19 04:35:48 +03:00
|
|
|
rv = mListener->OnMessageReceived(aMsg);
|
|
|
|
}
|
|
|
|
MaybeHandleError(rv, aMsg, "DispatchAsyncMessage");
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-05-17 00:02:43 +03:00
|
|
|
MessageChannel::DispatchInterruptMessage(Message&& aMsg, size_t stackDepth)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
IPC_ASSERT(aMsg.is_interrupt() && !aMsg.is_reply(), "wrong message type");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2017-04-21 22:43:08 +03:00
|
|
|
if (ShouldDeferInterruptMessage(aMsg, stackDepth)) {
|
|
|
|
// We now know the other side's stack has one more frame
|
|
|
|
// than we thought.
|
|
|
|
++mRemoteStackDepthGuess; // decremented in MaybeProcessDeferred()
|
2018-05-30 22:15:35 +03:00
|
|
|
mDeferred.push(std::move(aMsg));
|
2017-04-21 22:43:08 +03:00
|
|
|
return;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2017-04-21 22:43:08 +03:00
|
|
|
// If we "lost" a race and need to process the other side's in-call, we
|
|
|
|
// don't need to fix up the mRemoteStackDepthGuess here, because we're just
|
|
|
|
// about to increment it, which will make it correct again.
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
#ifdef OS_WIN
|
|
|
|
SyncStackFrame frame(this, true);
|
|
|
|
#endif
|
|
|
|
|
2014-10-28 23:53:15 +03:00
|
|
|
nsAutoPtr<Message> reply;
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
++mRemoteStackDepthGuess;
|
2014-10-28 23:53:15 +03:00
|
|
|
Result rv = mListener->OnCallReceived(aMsg, *getter_Transfers(reply));
|
2013-09-28 05:42:08 +04:00
|
|
|
--mRemoteStackDepthGuess;
|
|
|
|
|
2014-08-22 20:23:01 +04:00
|
|
|
if (!MaybeHandleError(rv, aMsg, "DispatchInterruptMessage")) {
|
Bug 1397823 - part 3 - do a better job setting IPC::Message flags; r=kanru
The current IPC::Message constructor takes a large number of arguments,
three of which--the nesting level, the priority, and the
compression--are almost always constant by virtue of the vast majority
of Message construction being done by auto-generated IPDL code. But
then we take these constant values into the Message constructor, we
check them for various values, and then based on those values, we
perform a bunch of bitfield operations to store flags based on those
values. This is wasted work.
Furthermore, for replies to IPDL messages, we'll construct a Message
object, and then call mutating setters on the Message object that will
perform even more bitfield manipulations. Again, these operations are
performing tasks at runtime that are the same every single time, and use
information we already have at compile time.
The impact of these extra operations is not large, maybe 15-30K of extra
code, depending on platform. Nonetheless, we can easily make them go
away, and make everything cleaner to boot.
This patch adds a HeaderFlags class that encapsulates all the knowledge
about the various kinds of flags Message needs to know about. We can
construct HeaderFlags objects with strongly-typed enum arguments for the
various kinds of flags, and the compiler can take care of folding all of
those flags together into a constant when possible (and it is possible
for all the IPDL-generated code that instantiates Messages). The upshot
is that we do no unnecessary work in the Message constructor itself. We
can also remove various mutating operations on Message, as those
operations were only there to support post-constructor flag twiddling,
which is no longer necessary.
2017-09-15 15:06:11 +03:00
|
|
|
reply = Message::ForInterruptDispatchError();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
reply->set_seqno(aMsg.seqno());
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
2014-10-28 23:53:15 +03:00
|
|
|
if (ChannelConnected == mChannelState) {
|
|
|
|
mLink->SendMessage(reply.forget());
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2017-04-21 22:43:08 +03:00
|
|
|
bool
|
|
|
|
MessageChannel::ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDepth)
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
|
|
|
|
// We may or may not own the lock in this function, so don't access any
|
|
|
|
// channel state.
|
|
|
|
|
|
|
|
IPC_ASSERT(aMsg.is_interrupt() && !aMsg.is_reply(), "wrong message type");
|
|
|
|
|
|
|
|
// Race detection: see the long comment near mRemoteStackDepthGuess in
|
|
|
|
// MessageChannel.h. "Remote" stack depth means our side, and "local" means
|
|
|
|
// the other side.
|
|
|
|
if (aMsg.interrupt_remote_stack_depth_guess() == RemoteViewOfStackDepth(aStackDepth)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interrupt in-calls have raced. The winner, if there is one, gets to defer
|
|
|
|
// processing of the other side's in-call.
|
|
|
|
bool defer;
|
|
|
|
const char* winner;
|
|
|
|
const MessageInfo parentMsgInfo =
|
|
|
|
(mSide == ChildSide) ? MessageInfo(aMsg) : mInterruptStack.top();
|
|
|
|
const MessageInfo childMsgInfo =
|
|
|
|
(mSide == ChildSide) ? mInterruptStack.top() : MessageInfo(aMsg);
|
|
|
|
switch (mListener->MediateInterruptRace(parentMsgInfo, childMsgInfo))
|
|
|
|
{
|
|
|
|
case RIPChildWins:
|
|
|
|
winner = "child";
|
|
|
|
defer = (mSide == ChildSide);
|
|
|
|
break;
|
|
|
|
case RIPParentWins:
|
|
|
|
winner = "parent";
|
|
|
|
defer = (mSide != ChildSide);
|
|
|
|
break;
|
|
|
|
case RIPError:
|
|
|
|
MOZ_CRASH("NYI: 'Error' Interrupt race policy");
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("not reached");
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC_LOG("race in %s: %s won",
|
|
|
|
(mSide == ChildSide) ? "child" : "parent",
|
|
|
|
winner);
|
|
|
|
|
|
|
|
return defer;
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
|
|
|
MessageChannel::MaybeUndeferIncall()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
if (mDeferred.empty())
|
|
|
|
return;
|
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
size_t stackDepth = InterruptStackDepth();
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2017-04-21 22:43:08 +03:00
|
|
|
Message& deferred = mDeferred.top();
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
// the other side can only *under*-estimate our actual stack depth
|
2017-04-21 22:43:08 +03:00
|
|
|
IPC_ASSERT(deferred.interrupt_remote_stack_depth_guess() <= stackDepth,
|
2013-09-28 05:42:08 +04:00
|
|
|
"fatal logic error");
|
|
|
|
|
2017-04-21 22:43:08 +03:00
|
|
|
if (ShouldDeferInterruptMessage(deferred, stackDepth)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
// maybe time to process this message
|
2018-05-30 22:15:35 +03:00
|
|
|
Message call(std::move(deferred));
|
2013-09-28 05:42:08 +04:00
|
|
|
mDeferred.pop();
|
|
|
|
|
|
|
|
// fix up fudge factor we added to account for race
|
|
|
|
IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
|
|
|
|
--mRemoteStackDepthGuess;
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
MOZ_RELEASE_ASSERT(call.nested_level() == IPC::Message::NOT_NESTED);
|
2018-05-30 22:15:35 +03:00
|
|
|
RefPtr<MessageTask> task = new MessageTask(this, std::move(call));
|
2016-10-15 21:47:14 +03:00
|
|
|
mPending.insertBack(task);
|
2017-04-11 07:44:56 +03:00
|
|
|
MOZ_ASSERT(IsAlwaysDeferred(task->Msg()));
|
2016-10-15 21:47:14 +03:00
|
|
|
task->Post();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2016-10-30 21:26:40 +03:00
|
|
|
void
|
|
|
|
MessageChannel::EnteredCxxStack()
|
|
|
|
{
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->EnteredCxxStack();
|
2016-10-30 21:26:40 +03:00
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
|
|
|
MessageChannel::ExitedCxxStack()
|
|
|
|
{
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->ExitedCxxStack();
|
2013-10-01 04:27:45 +04:00
|
|
|
if (mSawInterruptOutMsg) {
|
2013-09-28 05:42:08 +04:00
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
// see long comment in OnMaybeDequeueOne()
|
|
|
|
EnqueuePendingMessages();
|
2013-10-01 04:27:45 +04:00
|
|
|
mSawInterruptOutMsg = false;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-30 21:26:40 +03:00
|
|
|
void
|
|
|
|
MessageChannel::EnteredCall()
|
|
|
|
{
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->EnteredCall();
|
2016-10-30 21:26:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::ExitedCall()
|
|
|
|
{
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->ExitedCall();
|
2016-10-30 21:26:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::EnteredSyncSend()
|
|
|
|
{
|
|
|
|
mListener->OnEnteredSyncSend();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::ExitedSyncSend()
|
|
|
|
{
|
|
|
|
mListener->OnExitedSyncSend();
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
|
|
|
MessageChannel::EnqueuePendingMessages()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
MaybeUndeferIncall();
|
|
|
|
|
|
|
|
// XXX performance tuning knob: could process all or k pending
|
|
|
|
// messages here, rather than enqueuing for later processing
|
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
RepostAllMessages();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::WaitResponse(bool aWaitTimedOut)
|
|
|
|
{
|
|
|
|
if (aWaitTimedOut) {
|
|
|
|
if (mInTimeoutSecondHalf) {
|
|
|
|
// We've really timed out this time.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Try a second time.
|
|
|
|
mInTimeoutSecondHalf = true;
|
|
|
|
} else {
|
|
|
|
mInTimeoutSecondHalf = false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef OS_WIN
|
|
|
|
bool
|
2015-10-08 00:38:08 +03:00
|
|
|
MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2016-02-25 01:04:44 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
// WARNING: We don't release the lock here. We can't because the link thread
|
|
|
|
// could signal at this time and we would miss it. Instead we require
|
|
|
|
// ArtificialTimeout() to be extremely simple.
|
|
|
|
if (mListener->ArtificialTimeout()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-02-09 23:17:26 +03:00
|
|
|
TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
|
|
|
|
TimeDuration::Forever() :
|
|
|
|
TimeDuration::FromMilliseconds(mTimeoutMs);
|
|
|
|
CVStatus status = mMonitor->Wait(timeout);
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
// If the timeout didn't expire, we know we received an event. The
|
|
|
|
// converse is not true.
|
2018-02-09 23:17:26 +03:00
|
|
|
return WaitResponse(status == CVStatus::Timeout);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2013-10-01 04:27:45 +04:00
|
|
|
MessageChannel::WaitForInterruptNotify()
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2015-10-08 00:38:08 +03:00
|
|
|
return WaitForSyncNotify(true);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::NotifyWorkerThread()
|
|
|
|
{
|
|
|
|
mMonitor->Notify();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool
|
|
|
|
MessageChannel::ShouldContinueFromTimeout()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
bool cont;
|
|
|
|
{
|
|
|
|
MonitorAutoUnlock unlock(*mMonitor);
|
2016-11-02 02:50:07 +03:00
|
|
|
cont = mListener->ShouldContinueFromReplyTimeout();
|
2016-02-25 01:04:44 +03:00
|
|
|
mListener->ArtificialSleep();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static enum { UNKNOWN, NOT_DEBUGGING, DEBUGGING } sDebuggingChildren = UNKNOWN;
|
|
|
|
|
|
|
|
if (sDebuggingChildren == UNKNOWN) {
|
2017-03-09 12:37:10 +03:00
|
|
|
sDebuggingChildren = getenv("MOZ_DEBUG_CHILD_PROCESS") ||
|
|
|
|
getenv("MOZ_DEBUG_CHILD_PAUSE")
|
|
|
|
? DEBUGGING
|
|
|
|
: NOT_DEBUGGING;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
if (sDebuggingChildren == DEBUGGING) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::SetReplyTimeoutMs(int32_t aTimeoutMs)
|
|
|
|
{
|
|
|
|
// Set channel timeout value. Since this is broken up into
|
|
|
|
// two period, the minimum timeout value is 2ms.
|
|
|
|
AssertWorkerThread();
|
|
|
|
mTimeoutMs = (aTimeoutMs <= 0)
|
|
|
|
? kNoTimeout
|
|
|
|
: (int32_t)ceil((double)aTimeoutMs / 2.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::OnChannelConnected(int32_t peer_id)
|
|
|
|
{
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mPeerPidSet);
|
2014-08-21 22:13:23 +04:00
|
|
|
mPeerPidSet = true;
|
|
|
|
mPeerPid = peer_id;
|
2016-10-15 21:54:56 +03:00
|
|
|
RefPtr<CancelableRunnable> task = mOnChannelConnectedTask;
|
2017-09-23 02:31:07 +03:00
|
|
|
if (mWorkerLoop) {
|
|
|
|
mWorkerLoop->PostTask(task.forget());
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-08-21 22:13:23 +04:00
|
|
|
MessageChannel::DispatchOnChannelConnected()
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mPeerPidSet);
|
2016-08-10 11:53:00 +03:00
|
|
|
mListener->OnChannelConnected(mPeerPid);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2013-11-15 00:24:18 +04:00
|
|
|
void
|
|
|
|
MessageChannel::ReportMessageRouteError(const char* channelName) const
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2013-11-15 00:24:18 +04:00
|
|
|
PrintErrorMessage(mSide, channelName, "Need a route");
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->ProcessingError(MsgRouteError, "MsgRouteError");
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-04-16 02:43:21 +03:00
|
|
|
MessageChannel::ReportConnectionError(const char* aChannelName, Message* aMsg) const
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2013-11-22 20:29:25 +04:00
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
const char* errorMsg = nullptr;
|
|
|
|
switch (mChannelState) {
|
|
|
|
case ChannelClosed:
|
|
|
|
errorMsg = "Closed channel: cannot send/recv";
|
|
|
|
break;
|
|
|
|
case ChannelOpening:
|
|
|
|
errorMsg = "Opening channel: not yet ready for send/recv";
|
|
|
|
break;
|
|
|
|
case ChannelTimeout:
|
|
|
|
errorMsg = "Channel timeout: cannot send/recv";
|
|
|
|
break;
|
|
|
|
case ChannelClosing:
|
|
|
|
errorMsg = "Channel closing: too late to send/recv, messages will be lost";
|
|
|
|
break;
|
|
|
|
case ChannelError:
|
|
|
|
errorMsg = "Channel error: cannot send/recv";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("unreached");
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2015-04-16 02:43:21 +03:00
|
|
|
if (aMsg) {
|
|
|
|
char reason[512];
|
2016-08-15 09:44:00 +03:00
|
|
|
SprintfLiteral(reason,"(msgtype=0x%X,name=%s) %s",
|
|
|
|
aMsg->type(), aMsg->name(), errorMsg);
|
2015-04-16 02:43:21 +03:00
|
|
|
|
|
|
|
PrintErrorMessage(mSide, aChannelName, reason);
|
|
|
|
} else {
|
|
|
|
PrintErrorMessage(mSide, aChannelName, errorMsg);
|
|
|
|
}
|
2013-11-22 20:29:25 +04:00
|
|
|
|
|
|
|
MonitorAutoUnlock unlock(*mMonitor);
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->ProcessingError(MsgDropped, errorMsg);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2014-08-22 20:23:01 +04:00
|
|
|
MessageChannel::MaybeHandleError(Result code, const Message& aMsg, const char* channelName)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
if (MsgProcessed == code)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const char* errorMsg = nullptr;
|
|
|
|
switch (code) {
|
|
|
|
case MsgNotKnown:
|
|
|
|
errorMsg = "Unknown message: not processed";
|
|
|
|
break;
|
|
|
|
case MsgNotAllowed:
|
|
|
|
errorMsg = "Message not allowed: cannot be sent/recvd in this state";
|
|
|
|
break;
|
|
|
|
case MsgPayloadError:
|
|
|
|
errorMsg = "Payload error: message could not be deserialized";
|
|
|
|
break;
|
|
|
|
case MsgProcessingError:
|
|
|
|
errorMsg = "Processing error: message was deserialized, but the handler returned false (indicating failure)";
|
|
|
|
break;
|
|
|
|
case MsgRouteError:
|
|
|
|
errorMsg = "Route error: message sent to unknown actor ID";
|
|
|
|
break;
|
|
|
|
case MsgValueError:
|
|
|
|
errorMsg = "Value error: message was deserialized, but contained an illegal value";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("unknown Result code");
|
2013-09-28 05:42:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-03 20:09:27 +03:00
|
|
|
char reason[512];
|
2017-09-14 11:08:57 +03:00
|
|
|
const char* msgname = aMsg.name();
|
2016-10-20 17:26:52 +03:00
|
|
|
if (msgname[0] == '?') {
|
|
|
|
SprintfLiteral(reason,"(msgtype=0x%X) %s", aMsg.type(), errorMsg);
|
|
|
|
} else {
|
|
|
|
SprintfLiteral(reason,"%s %s", msgname, errorMsg);
|
|
|
|
}
|
2014-08-22 20:23:01 +04:00
|
|
|
|
2015-02-03 20:09:27 +03:00
|
|
|
PrintErrorMessage(mSide, channelName, reason);
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2016-11-15 06:26:00 +03:00
|
|
|
// Error handled in mozilla::ipc::IPCResult.
|
|
|
|
if (code == MsgProcessingError) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-02 02:50:07 +03:00
|
|
|
mListener->ProcessingError(code, reason);
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::OnChannelErrorFromLink()
|
|
|
|
{
|
|
|
|
AssertLinkThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2016-01-23 04:45:43 +03:00
|
|
|
IPC_LOG("OnChannelErrorFromLink");
|
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
if (InterruptStackDepth() > 0)
|
2013-09-28 05:42:08 +04:00
|
|
|
NotifyWorkerThread();
|
|
|
|
|
2014-12-30 02:12:47 +03:00
|
|
|
if (AwaitingSyncReply() || AwaitingIncomingMessage())
|
2013-09-28 05:42:08 +04:00
|
|
|
NotifyWorkerThread();
|
|
|
|
|
|
|
|
if (ChannelClosing != mChannelState) {
|
2014-03-04 21:17:01 +04:00
|
|
|
if (mAbortOnError) {
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("Aborting on channel error.");
|
2014-03-04 21:17:01 +04:00
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
mChannelState = ChannelError;
|
|
|
|
mMonitor->Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
PostErrorNotifyTask();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::NotifyMaybeChannelError()
|
|
|
|
{
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
// TODO sort out Close() on this side racing with Close() on the other side
|
|
|
|
if (ChannelClosing == mChannelState) {
|
|
|
|
// the channel closed, but we received a "Goodbye" message warning us
|
|
|
|
// about it. no worries
|
|
|
|
mChannelState = ChannelClosed;
|
|
|
|
NotifyChannelClosed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-13 21:21:58 +03:00
|
|
|
Clear();
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
// Oops, error! Let the listener know about it.
|
|
|
|
mChannelState = ChannelError;
|
2016-07-13 21:21:58 +03:00
|
|
|
|
2016-09-20 05:17:09 +03:00
|
|
|
// IPDL assumes these notifications do not fire twice, so we do not let
|
|
|
|
// that happen.
|
|
|
|
if (mNotifiedChannelDone) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mNotifiedChannelDone = true;
|
|
|
|
|
2016-08-10 11:53:00 +03:00
|
|
|
// After this, the channel may be deleted. Based on the premise that
|
|
|
|
// mListener owns this channel, any calls back to this class that may
|
|
|
|
// work with mListener should still work on living objects.
|
2013-09-28 05:42:08 +04:00
|
|
|
mListener->OnChannelError();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::OnNotifyMaybeChannelError()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
mChannelErrorTask = nullptr;
|
|
|
|
|
|
|
|
// OnChannelError holds mMonitor when it posts this task and this
|
|
|
|
// task cannot be allowed to run until OnChannelError has
|
|
|
|
// exited. We enforce that order by grabbing the mutex here which
|
|
|
|
// should only continue once OnChannelError has completed.
|
|
|
|
{
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
// nothing to do here
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsOnCxxStack()) {
|
2017-06-12 22:34:10 +03:00
|
|
|
mChannelErrorTask = NewNonOwningCancelableRunnableMethod(
|
|
|
|
"ipc::MessageChannel::OnNotifyMaybeChannelError",
|
|
|
|
this,
|
|
|
|
&MessageChannel::OnNotifyMaybeChannelError);
|
|
|
|
RefPtr<Runnable> task = mChannelErrorTask;
|
|
|
|
// 10 ms delay is completely arbitrary
|
2017-09-23 02:31:07 +03:00
|
|
|
if (mWorkerLoop) {
|
|
|
|
mWorkerLoop->PostDelayedTask(task.forget(), 10);
|
|
|
|
}
|
2017-06-12 22:34:10 +03:00
|
|
|
return;
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NotifyMaybeChannelError();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::PostErrorNotifyTask()
|
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2017-09-23 02:31:07 +03:00
|
|
|
if (mChannelErrorTask || !mWorkerLoop)
|
2013-09-28 05:42:08 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
// This must be the last code that runs on this thread!
|
2017-06-12 22:34:10 +03:00
|
|
|
mChannelErrorTask = NewNonOwningCancelableRunnableMethod(
|
|
|
|
"ipc::MessageChannel::OnNotifyMaybeChannelError",
|
|
|
|
this,
|
|
|
|
&MessageChannel::OnNotifyMaybeChannelError);
|
2016-04-28 03:06:05 +03:00
|
|
|
RefPtr<Runnable> task = mChannelErrorTask;
|
|
|
|
mWorkerLoop->PostTask(task.forget());
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Special async message.
|
|
|
|
class GoodbyeMessage : public IPC::Message
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
GoodbyeMessage() :
|
2016-10-01 02:20:50 +03:00
|
|
|
IPC::Message(MSG_ROUTING_NONE, GOODBYE_MESSAGE_TYPE)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
static bool Read(const Message* msg) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void Log(const std::string& aPrefix, FILE* aOutf) const {
|
|
|
|
fputs("(special `Goodbye' message)", aOutf);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::SynchronouslyClose()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
mLink->SendClose();
|
|
|
|
while (ChannelClosed != mChannelState)
|
|
|
|
mMonitor->Wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::CloseWithError()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
if (ChannelConnected != mChannelState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SynchronouslyClose();
|
|
|
|
mChannelState = ChannelError;
|
|
|
|
PostErrorNotifyTask();
|
|
|
|
}
|
|
|
|
|
2014-12-19 04:35:44 +03:00
|
|
|
void
|
|
|
|
MessageChannel::CloseWithTimeout()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
if (ChannelConnected != mChannelState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SynchronouslyClose();
|
|
|
|
mChannelState = ChannelTimeout;
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
void
|
|
|
|
MessageChannel::Close()
|
|
|
|
{
|
|
|
|
AssertWorkerThread();
|
|
|
|
|
|
|
|
{
|
2018-04-27 03:14:22 +03:00
|
|
|
// We don't use MonitorAutoLock here as that causes some sort of
|
|
|
|
// deadlock in the error/timeout-with-a-listener state below when
|
|
|
|
// compiling an optimized msvc build.
|
|
|
|
mMonitor->Lock();
|
|
|
|
|
|
|
|
// Instead just use a ScopeExit to manage the unlock.
|
|
|
|
RefPtr<RefCountedMonitor> monitor(mMonitor);
|
2018-05-30 22:15:35 +03:00
|
|
|
auto exit = MakeScopeExit([m = std::move(monitor)] () {
|
2018-04-27 03:14:22 +03:00
|
|
|
m->Unlock();
|
|
|
|
});
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
if (ChannelError == mChannelState || ChannelTimeout == mChannelState) {
|
|
|
|
// See bug 538586: if the listener gets deleted while the
|
|
|
|
// IO thread's NotifyChannelError event is still enqueued
|
|
|
|
// and subsequently deletes us, then the error event will
|
|
|
|
// also be deleted and the listener will never be notified
|
|
|
|
// of the channel error.
|
|
|
|
if (mListener) {
|
2018-04-27 03:14:22 +03:00
|
|
|
exit.release(); // Explicitly unlocking, clear scope exit.
|
|
|
|
mMonitor->Unlock();
|
2013-09-28 05:42:08 +04:00
|
|
|
NotifyMaybeChannelError();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-27 11:59:41 +04:00
|
|
|
if (ChannelOpening == mChannelState) {
|
2014-07-10 01:39:18 +04:00
|
|
|
// SynchronouslyClose() waits for an ack from the other side, so
|
|
|
|
// the opening sequence should complete before this returns.
|
2013-11-27 11:59:41 +04:00
|
|
|
SynchronouslyClose();
|
|
|
|
mChannelState = ChannelError;
|
2014-07-10 01:39:18 +04:00
|
|
|
NotifyMaybeChannelError();
|
2013-11-27 11:59:41 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-05 04:31:30 +03:00
|
|
|
if (ChannelClosed == mChannelState) {
|
2013-09-28 05:42:08 +04:00
|
|
|
// XXX be strict about this until there's a compelling reason
|
|
|
|
// to relax
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("Close() called on closed channel!");
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2016-11-05 04:31:30 +03:00
|
|
|
// Notify the other side that we're about to close our socket. If we've
|
|
|
|
// already received a Goodbye from the other side (and our state is
|
|
|
|
// ChannelClosing), there's no reason to send one.
|
|
|
|
if (ChannelConnected == mChannelState) {
|
|
|
|
mLink->SendMessage(new GoodbyeMessage());
|
|
|
|
}
|
2013-09-28 05:42:08 +04:00
|
|
|
SynchronouslyClose();
|
|
|
|
}
|
|
|
|
|
|
|
|
NotifyChannelClosed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::NotifyChannelClosed()
|
|
|
|
{
|
|
|
|
mMonitor->AssertNotCurrentThreadOwns();
|
|
|
|
|
|
|
|
if (ChannelClosed != mChannelState)
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("channel should have been closed!");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2016-07-13 21:21:58 +03:00
|
|
|
Clear();
|
|
|
|
|
2016-09-20 05:17:09 +03:00
|
|
|
// IPDL assumes these notifications do not fire twice, so we do not let
|
|
|
|
// that happen.
|
|
|
|
if (mNotifiedChannelDone) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mNotifiedChannelDone = true;
|
|
|
|
|
2013-09-28 05:42:08 +04:00
|
|
|
// OK, the IO thread just closed the channel normally. Let the
|
2016-07-13 21:21:58 +03:00
|
|
|
// listener know about it. After this point the channel may be
|
|
|
|
// deleted.
|
2013-09-28 05:42:08 +04:00
|
|
|
mListener->OnChannelClose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::DebugAbort(const char* file, int line, const char* cond,
|
|
|
|
const char* why,
|
2016-05-17 00:02:43 +03:00
|
|
|
bool reply)
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2013-10-01 04:27:45 +04:00
|
|
|
printf_stderr("###!!! [MessageChannel][%s][%s:%d] "
|
2013-09-28 05:42:08 +04:00
|
|
|
"Assertion (%s) failed. %s %s\n",
|
|
|
|
mSide == ChildSide ? "Child" : "Parent",
|
|
|
|
file, line, cond,
|
|
|
|
why,
|
|
|
|
reply ? "(reply)" : "");
|
|
|
|
// technically we need the mutex for this, but we're dying anyway
|
2013-10-01 04:27:45 +04:00
|
|
|
DumpInterruptStack(" ");
|
2017-07-26 23:03:57 +03:00
|
|
|
printf_stderr(" remote Interrupt stack guess: %zu\n",
|
2013-09-28 05:42:08 +04:00
|
|
|
mRemoteStackDepthGuess);
|
2017-07-26 23:03:57 +03:00
|
|
|
printf_stderr(" deferred stack size: %zu\n",
|
2013-09-28 05:42:08 +04:00
|
|
|
mDeferred.size());
|
2017-07-26 23:03:57 +03:00
|
|
|
printf_stderr(" out-of-turn Interrupt replies stack size: %zu\n",
|
2013-09-28 05:42:08 +04:00
|
|
|
mOutOfTurnReplies.size());
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
MessageQueue pending = std::move(mPending);
|
2016-10-15 21:47:14 +03:00
|
|
|
while (!pending.isEmpty()) {
|
2013-09-28 05:42:08 +04:00
|
|
|
printf_stderr(" [ %s%s ]\n",
|
2016-10-15 21:47:14 +03:00
|
|
|
pending.getFirst()->Msg().is_interrupt() ? "intr" :
|
|
|
|
(pending.getFirst()->Msg().is_sync() ? "sync" : "async"),
|
|
|
|
pending.getFirst()->Msg().is_reply() ? "reply" : "");
|
|
|
|
pending.popFirst();
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
2017-10-25 09:38:38 +03:00
|
|
|
MOZ_CRASH_UNSAFE_OOL(why);
|
2013-09-28 05:42:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-01 04:27:45 +04:00
|
|
|
MessageChannel::DumpInterruptStack(const char* const pfx) const
|
2013-09-28 05:42:08 +04:00
|
|
|
{
|
2016-09-01 08:01:16 +03:00
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
MessageLoop::current() != mWorkerLoop,
|
|
|
|
"The worker thread had better be paused in a debugger!");
|
2013-09-28 05:42:08 +04:00
|
|
|
|
2013-10-01 04:27:45 +04:00
|
|
|
printf_stderr("%sMessageChannel 'backtrace':\n", pfx);
|
2013-09-28 05:42:08 +04:00
|
|
|
|
|
|
|
// print a python-style backtrace, first frame to last
|
2014-01-11 00:58:20 +04:00
|
|
|
for (uint32_t i = 0; i < mCxxStackFrames.length(); ++i) {
|
2013-09-28 05:42:08 +04:00
|
|
|
int32_t id;
|
2014-08-08 18:04:45 +04:00
|
|
|
const char* dir;
|
|
|
|
const char* sems;
|
|
|
|
const char* name;
|
2013-09-28 05:42:08 +04:00
|
|
|
mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);
|
|
|
|
|
|
|
|
printf_stderr("%s[(%u) %s %s %s(actor=%d) ]\n", pfx,
|
|
|
|
i, dir, sems, name, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-19 09:05:54 +03:00
|
|
|
int32_t
|
|
|
|
MessageChannel::GetTopmostMessageRoutingId() const
|
|
|
|
{
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(MessageLoop::current() == mWorkerLoop);
|
2015-02-19 09:05:54 +03:00
|
|
|
if (mCxxStackFrames.empty()) {
|
|
|
|
return MSG_ROUTING_NONE;
|
|
|
|
}
|
|
|
|
const InterruptFrame& frame = mCxxStackFrames.back();
|
|
|
|
return frame.GetRoutingId();
|
|
|
|
}
|
|
|
|
|
2016-01-23 05:02:27 +03:00
|
|
|
void
|
|
|
|
MessageChannel::EndTimeout()
|
|
|
|
{
|
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
IPC_LOG("Ending timeout of seqno=%d", mTimedOutMessageSeqno);
|
|
|
|
mTimedOutMessageSeqno = 0;
|
2016-10-01 02:20:50 +03:00
|
|
|
mTimedOutMessageNestedLevel = 0;
|
2016-01-23 05:02:27 +03:00
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
RepostAllMessages();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MessageChannel::RepostAllMessages()
|
|
|
|
{
|
|
|
|
bool needRepost = false;
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* task : mPending) {
|
2016-10-15 21:47:14 +03:00
|
|
|
if (!task->IsScheduled()) {
|
|
|
|
needRepost = true;
|
2018-03-23 16:40:53 +03:00
|
|
|
break;
|
2016-10-15 21:47:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!needRepost) {
|
|
|
|
// If everything is already scheduled to run, do nothing.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// In some cases we may have deferred dispatch of some messages in the
|
|
|
|
// queue. Now we want to run them again. However, we can't just re-post
|
|
|
|
// those messages since the messages after them in mPending would then be
|
|
|
|
// before them in the event queue. So instead we cancel everything and
|
|
|
|
// re-post all messages in the correct order.
|
2018-05-30 22:15:35 +03:00
|
|
|
MessageQueue queue = std::move(mPending);
|
2016-10-15 21:47:14 +03:00
|
|
|
while (RefPtr<MessageTask> task = queue.popFirst()) {
|
2018-05-30 22:15:35 +03:00
|
|
|
RefPtr<MessageTask> newTask = new MessageTask(this, std::move(task->Msg()));
|
2016-10-15 21:47:14 +03:00
|
|
|
mPending.insertBack(newTask);
|
|
|
|
newTask->Post();
|
2016-01-23 05:02:27 +03:00
|
|
|
}
|
2017-04-11 07:44:56 +03:00
|
|
|
|
|
|
|
AssertMaybeDeferredCountCorrect();
|
2016-01-23 05:02:27 +03:00
|
|
|
}
|
|
|
|
|
2016-01-23 05:02:27 +03:00
|
|
|
void
|
2016-01-23 04:52:23 +03:00
|
|
|
MessageChannel::CancelTransaction(int transaction)
|
2015-06-19 21:32:35 +03:00
|
|
|
{
|
2016-01-20 04:23:28 +03:00
|
|
|
mMonitor->AssertCurrentThreadOwns();
|
|
|
|
|
2015-06-19 21:32:35 +03:00
|
|
|
// When we cancel a transaction, we need to behave as if there's no longer
|
|
|
|
// any IPC on the stack. Anything we were dispatching or sending will get
|
|
|
|
// canceled. Consequently, we have to update the state variables below.
|
|
|
|
//
|
|
|
|
// We also need to ensure that when any IPC functions on the stack return,
|
|
|
|
// they don't reset these values using an RAII class like AutoSetValue. To
|
|
|
|
// avoid that, these RAII classes check if the variable they set has been
|
|
|
|
// tampered with (by us). If so, they don't reset the variable to the old
|
|
|
|
// value.
|
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
IPC_LOG("CancelTransaction: xid=%d", transaction);
|
2016-01-23 04:58:54 +03:00
|
|
|
|
2016-01-23 04:52:23 +03:00
|
|
|
// An unusual case: We timed out a transaction which the other side then
|
|
|
|
// cancelled. In this case we just leave the timedout state and try to
|
|
|
|
// forget this ever happened.
|
|
|
|
if (transaction == mTimedOutMessageSeqno) {
|
|
|
|
IPC_LOG("Cancelled timed out message %d", mTimedOutMessageSeqno);
|
2016-01-23 05:02:27 +03:00
|
|
|
EndTimeout();
|
2016-01-23 04:52:23 +03:00
|
|
|
|
|
|
|
// Normally mCurrentTransaction == 0 here. But it can be non-zero if:
|
2016-10-01 02:20:50 +03:00
|
|
|
// 1. Parent sends NESTED_INSIDE_SYNC message H.
|
2016-01-23 04:52:23 +03:00
|
|
|
// 2. Parent times out H.
|
|
|
|
// 3. Child dispatches H and sends nested message H' (same transaction).
|
|
|
|
// 4. Parent dispatches H' and cancels.
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!mTransactionStack || mTransactionStack->TransactionID() == transaction);
|
|
|
|
if (mTransactionStack) {
|
|
|
|
mTransactionStack->Cancel();
|
|
|
|
}
|
2016-01-23 04:52:23 +03:00
|
|
|
} else {
|
2016-02-24 02:36:06 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mTransactionStack->TransactionID() == transaction);
|
|
|
|
mTransactionStack->Cancel();
|
2016-01-23 04:52:23 +03:00
|
|
|
}
|
|
|
|
|
2016-02-05 03:09:11 +03:00
|
|
|
bool foundSync = false;
|
2017-04-11 06:40:00 +03:00
|
|
|
for (MessageTask* p = mPending.getFirst(); p; ) {
|
2016-10-15 21:47:14 +03:00
|
|
|
Message &msg = p->Msg();
|
2016-01-23 04:52:23 +03:00
|
|
|
|
|
|
|
// If there was a race between the parent and the child, then we may
|
|
|
|
// have a queued sync message. We want to drop this message from the
|
2016-02-24 02:36:06 +03:00
|
|
|
// queue since if will get cancelled along with the transaction being
|
2016-10-01 02:20:50 +03:00
|
|
|
// cancelled. This happens if the message in the queue is NESTED_INSIDE_SYNC.
|
|
|
|
if (msg.is_sync() && msg.nested_level() != IPC::Message::NOT_NESTED) {
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!foundSync);
|
|
|
|
MOZ_RELEASE_ASSERT(msg.transaction_id() != transaction);
|
2016-01-23 04:52:23 +03:00
|
|
|
IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id());
|
|
|
|
foundSync = true;
|
2017-04-11 07:44:56 +03:00
|
|
|
if (!IsAlwaysDeferred(msg)) {
|
|
|
|
mMaybeDeferredPendingCount--;
|
|
|
|
}
|
2016-10-15 21:47:14 +03:00
|
|
|
p = p->removeAndGetNext();
|
2016-01-23 04:52:23 +03:00
|
|
|
continue;
|
|
|
|
}
|
2016-01-26 20:55:59 +03:00
|
|
|
|
2016-10-15 21:47:14 +03:00
|
|
|
p = p->getNext();
|
2016-01-20 04:37:46 +03:00
|
|
|
}
|
2017-04-11 07:44:56 +03:00
|
|
|
|
|
|
|
AssertMaybeDeferredCountCorrect();
|
2016-02-24 02:36:06 +03:00
|
|
|
}
|
2016-01-20 04:37:46 +03:00
|
|
|
|
2016-02-24 02:36:06 +03:00
|
|
|
bool
|
|
|
|
MessageChannel::IsInTransaction() const
|
|
|
|
{
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
|
|
|
return !!mTransactionStack;
|
2015-06-19 21:32:35 +03:00
|
|
|
}
|
|
|
|
|
2015-10-07 21:13:48 +03:00
|
|
|
void
|
2015-06-19 21:32:35 +03:00
|
|
|
MessageChannel::CancelCurrentTransaction()
|
|
|
|
{
|
|
|
|
MonitorAutoLock lock(*mMonitor);
|
2016-10-01 02:20:50 +03:00
|
|
|
if (DispatchingSyncMessageNestedLevel() >= IPC::Message::NESTED_INSIDE_SYNC) {
|
|
|
|
if (DispatchingSyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW ||
|
|
|
|
DispatchingAsyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW)
|
2016-01-20 04:38:17 +03:00
|
|
|
{
|
2016-01-23 04:58:54 +03:00
|
|
|
mListener->IntentionalCrash();
|
2016-01-20 04:38:17 +03:00
|
|
|
}
|
|
|
|
|
2016-10-01 02:20:50 +03:00
|
|
|
IPC_LOG("Cancel requested: current xid=%d", CurrentNestedInsideSyncTransaction());
|
2016-02-05 03:09:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(DispatchingSyncMessage());
|
2016-10-01 02:20:50 +03:00
|
|
|
CancelMessage *cancel = new CancelMessage(CurrentNestedInsideSyncTransaction());
|
|
|
|
CancelTransaction(CurrentNestedInsideSyncTransaction());
|
2016-01-23 04:45:43 +03:00
|
|
|
mLink->SendMessage(cancel);
|
2015-07-14 00:34:42 +03:00
|
|
|
}
|
2015-06-19 21:32:35 +03:00
|
|
|
}
|
|
|
|
|
2015-06-24 03:52:01 +03:00
|
|
|
void
|
|
|
|
CancelCPOWs()
|
2014-08-06 08:43:36 +04:00
|
|
|
{
|
2015-10-07 21:13:48 +03:00
|
|
|
if (gParentProcessBlocker) {
|
2015-07-01 03:12:30 +03:00
|
|
|
mozilla::Telemetry::Accumulate(mozilla::Telemetry::IPC_TRANSACTION_CANCEL, true);
|
2015-10-07 21:13:48 +03:00
|
|
|
gParentProcessBlocker->CancelCurrentTransaction();
|
2015-06-24 03:52:01 +03:00
|
|
|
}
|
2014-08-06 08:43:36 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace ipc
|
|
|
|
} // namespace mozilla
|