/work/obj-fuzz/dist/include/mozilla/ipc/MessageChannel.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: sw=4 ts=4 et : |
3 | | */ |
4 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | #ifndef ipc_glue_MessageChannel_h |
9 | | #define ipc_glue_MessageChannel_h 1 |
10 | | |
11 | | #include "base/basictypes.h" |
12 | | #include "base/message_loop.h" |
13 | | |
14 | | #include "nsIMemoryReporter.h" |
15 | | #include "mozilla/Atomics.h" |
16 | | #include "mozilla/DebugOnly.h" |
17 | | #include "mozilla/Monitor.h" |
18 | | #include "mozilla/MozPromise.h" |
19 | | #include "mozilla/Vector.h" |
20 | | #if defined(OS_WIN) |
21 | | #include "mozilla/ipc/Neutering.h" |
22 | | #endif // defined(OS_WIN) |
23 | | #include "mozilla/ipc/Transport.h" |
24 | | #include "MessageLink.h" |
25 | | #include "nsILabelableRunnable.h" |
26 | | #include "nsThreadUtils.h" |
27 | | |
28 | | #include <deque> |
29 | | #include <functional> |
30 | | #include <map> |
31 | | #include <math.h> |
32 | | #include <stack> |
33 | | #include <vector> |
34 | | |
35 | | class nsIEventTarget; |
36 | | |
37 | | namespace mozilla { |
38 | | namespace ipc { |
39 | | |
40 | | class MessageChannel; |
41 | | class IToplevelProtocol; |
42 | | |
43 | | class RefCountedMonitor : public Monitor |
44 | | { |
45 | | public: |
46 | | RefCountedMonitor() |
47 | | : Monitor("mozilla.ipc.MessageChannel.mMonitor") |
48 | 0 | {} |
49 | | |
50 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor) |
51 | | |
52 | | private: |
53 | 0 | ~RefCountedMonitor() {} |
54 | | }; |
55 | | |
56 | | enum class SyncSendError { |
57 | | SendSuccess, |
58 | | PreviousTimeout, |
59 | | SendingCPOWWhileDispatchingSync, |
60 | | SendingCPOWWhileDispatchingUrgent, |
61 | | NotConnectedBeforeSend, |
62 | | DisconnectedDuringSend, |
63 | | CancelledBeforeSend, |
64 | | CancelledAfterSend, |
65 | | TimedOut, |
66 | | ReplyError, |
67 | | }; |
68 | | |
69 | | enum class ResponseRejectReason { |
70 | | SendError, |
71 | | ChannelClosed, |
72 | | HandlerRejected, |
73 | | ActorDestroyed, |
74 | | EndGuard_, |
75 | | }; |
76 | | |
77 | | template<typename T> |
78 | | using ResolveCallback = std::function<void (T&&)>; |
79 | | |
80 | | using RejectCallback = std::function<void (ResponseRejectReason)>; |
81 | | |
82 | | enum ChannelState { |
83 | | ChannelClosed, |
84 | | ChannelOpening, |
85 | | ChannelConnected, |
86 | | ChannelTimeout, |
87 | | ChannelClosing, |
88 | | ChannelError |
89 | | }; |
90 | | |
91 | | class AutoEnterTransaction; |
92 | | |
93 | | class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver |
94 | | { |
95 | | friend class ProcessLink; |
96 | | friend class ThreadLink; |
97 | | #ifdef FUZZING |
98 | | friend class ProtocolFuzzerHelper; |
99 | | #endif |
100 | | |
101 | | class CxxStackFrame; |
102 | | class InterruptFrame; |
103 | | |
104 | | typedef mozilla::Monitor Monitor; |
105 | | |
106 | | // We could templatize the actor type but it would unnecessarily |
107 | | // expand the code size. Using the actor address as the |
108 | | // identifier is already good enough. |
109 | | typedef void* ActorIdType; |
110 | | |
111 | | public: |
112 | | struct UntypedCallbackHolder |
113 | | { |
114 | | UntypedCallbackHolder(ActorIdType aActorId, |
115 | | RejectCallback&& aReject) |
116 | | : mActorId(aActorId) |
117 | | , mReject(std::move(aReject)) |
118 | 0 | {} |
119 | | |
120 | 0 | virtual ~UntypedCallbackHolder() {} |
121 | | |
122 | 0 | void Reject(ResponseRejectReason aReason) { |
123 | 0 | mReject(aReason); |
124 | 0 | } |
125 | | |
126 | | ActorIdType mActorId; |
127 | | RejectCallback mReject; |
128 | | }; |
129 | | |
130 | | template<typename Value> |
131 | | struct CallbackHolder : public UntypedCallbackHolder |
132 | | { |
133 | | CallbackHolder(ActorIdType aActorId, |
134 | | ResolveCallback<Value>&& aResolve, |
135 | | RejectCallback&& aReject) |
136 | | : UntypedCallbackHolder(aActorId, std::move(aReject)) |
137 | | , mResolve(std::move(aResolve)) |
138 | 0 | {} Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::wr::MemoryReport>::CallbackHolder(void*, std::__1::function<void (mozilla::wr::MemoryReport&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild> >::CallbackHolder(void*, std::__1::function<void (mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::FileDescriptor>::CallbackHolder(void*, std::__1::function<void (mozilla::ipc::FileDescriptor&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::CreatedWindowInfo>::CallbackHolder(void*, std::__1::function<void (mozilla::dom::CreatedWindowInfo&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<bool>::CallbackHolder(void*, std::__1::function<void (bool&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<RefPtr<nsIInputStream> >::CallbackHolder(void*, std::__1::function<void (RefPtr<nsIInputStream>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Shmem>::CallbackHolder(void*, std::__1::function<void (mozilla::ipc::Shmem&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, nsTString<char16_t> > >::CallbackHolder(void*, std::__1::function<void (mozilla::Tuple<bool, nsTString<char16_t> >&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult>::CallbackHolder(void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult>::CallbackHolder(void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, mozilla::CopyableErrorResult> >::CallbackHolder(void*, std::__1::function<void (mozilla::Tuple<bool, mozilla::CopyableErrorResult>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::widget::IMENotificationRequests>::CallbackHolder(void*, std::__1::function<void (mozilla::widget::IMENotificationRequests&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) |
139 | | |
140 | 0 | void Resolve(Value&& aReason) { |
141 | 0 | mResolve(std::move(aReason)); |
142 | 0 | } Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::wr::MemoryReport>::Resolve(mozilla::wr::MemoryReport&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild> >::Resolve(mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::FileDescriptor>::Resolve(mozilla::ipc::FileDescriptor&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::CreatedWindowInfo>::Resolve(mozilla::dom::CreatedWindowInfo&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<bool>::Resolve(bool&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<RefPtr<nsIInputStream> >::Resolve(RefPtr<nsIInputStream>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Shmem>::Resolve(mozilla::ipc::Shmem&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, nsTString<char16_t> > >::Resolve(mozilla::Tuple<bool, nsTString<char16_t> >&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult>::Resolve(mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult>::Resolve(mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, mozilla::CopyableErrorResult> >::Resolve(mozilla::Tuple<bool, mozilla::CopyableErrorResult>&&) Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::widget::IMENotificationRequests>::Resolve(mozilla::widget::IMENotificationRequests&&) |
143 | | |
144 | | ResolveCallback<Value> mResolve; |
145 | | }; |
146 | | |
147 | | private: |
148 | | static Atomic<size_t> gUnresolvedResponses; |
149 | | friend class PendingResponseReporter; |
150 | | |
151 | | public: |
152 | | static const int32_t kNoTimeout; |
153 | | |
154 | | typedef IPC::Message Message; |
155 | | typedef IPC::MessageInfo MessageInfo; |
156 | | typedef mozilla::ipc::Transport Transport; |
157 | | |
158 | | explicit MessageChannel(const char *aName, |
159 | | IToplevelProtocol *aListener); |
160 | | ~MessageChannel(); |
161 | | |
162 | 0 | IToplevelProtocol *Listener() const { |
163 | 0 | return mListener; |
164 | 0 | } |
165 | | |
166 | | // "Open" from the perspective of the transport layer; the underlying |
167 | | // socketpair/pipe should already be created. |
168 | | // |
169 | | // Returns true if the transport layer was successfully connected, |
170 | | // i.e., mChannelState == ChannelConnected. |
171 | | bool Open(Transport* aTransport, MessageLoop* aIOLoop=0, Side aSide=UnknownSide); |
172 | | |
173 | | // "Open" a connection to another thread in the same process. |
174 | | // |
175 | | // Returns true if the transport layer was successfully connected, |
176 | | // i.e., mChannelState == ChannelConnected. |
177 | | // |
178 | | // For more details on the process of opening a channel between |
179 | | // threads, see the extended comment on this function |
180 | | // in MessageChannel.cpp. |
181 | | bool Open(MessageChannel *aTargetChan, nsIEventTarget *aEventTarget, Side aSide); |
182 | | |
183 | | // Close the underlying transport channel. |
184 | | void Close(); |
185 | | |
186 | | // Force the channel to behave as if a channel error occurred. Valid |
187 | | // for process links only, not thread links. |
188 | | void CloseWithError(); |
189 | | |
190 | | void CloseWithTimeout(); |
191 | | |
192 | | void SetAbortOnError(bool abort) |
193 | 0 | { |
194 | 0 | mAbortOnError = abort; |
195 | 0 | } |
196 | | |
197 | | // Call aInvoke for each pending message until it returns false. |
198 | | // XXX: You must get permission from an IPC peer to use this function |
199 | | // since it requires custom deserialization and re-orders events. |
200 | | void PeekMessages(const std::function<bool(const Message& aMsg)>& aInvoke); |
201 | | |
202 | | // Misc. behavioral traits consumers can request for this channel |
203 | | enum ChannelFlags { |
204 | | REQUIRE_DEFAULT = 0, |
205 | | // Windows: if this channel operates on the UI thread, indicates |
206 | | // WindowsMessageLoop code should enable deferred native message |
207 | | // handling to prevent deadlocks. Should only be used for protocols |
208 | | // that manage child processes which might create native UI, like |
209 | | // plugins. |
210 | | REQUIRE_DEFERRED_MESSAGE_PROTECTION = 1 << 0, |
211 | | // Windows: When this flag is specified, any wait that occurs during |
212 | | // synchronous IPC will be alertable, thus allowing a11y code in the |
213 | | // chrome process to reenter content while content is waiting on a |
214 | | // synchronous call. |
215 | | REQUIRE_A11Y_REENTRY = 1 << 1, |
216 | | }; |
217 | 0 | void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; } |
218 | 0 | ChannelFlags GetChannelFlags() { return mFlags; } |
219 | | |
220 | | // Asynchronously send a message to the other side of the channel |
221 | | bool Send(Message* aMsg); |
222 | | |
223 | | // Asynchronously send a message to the other side of the channel |
224 | | // and wait for asynchronous reply. |
225 | | template<typename Value> |
226 | | void Send(Message* aMsg, |
227 | | ActorIdType aActorId, |
228 | | ResolveCallback<Value>&& aResolve, |
229 | 0 | RejectCallback&& aReject) { |
230 | 0 | int32_t seqno = NextSeqno(); |
231 | 0 | aMsg->set_seqno(seqno); |
232 | 0 | if (!Send(aMsg)) { |
233 | 0 | aReject(ResponseRejectReason::SendError); |
234 | 0 | return; |
235 | 0 | } |
236 | 0 | |
237 | 0 | UniquePtr<UntypedCallbackHolder> callback = |
238 | 0 | MakeUnique<CallbackHolder<Value>>( |
239 | 0 | aActorId, std::move(aResolve), std::move(aReject)); |
240 | 0 | mPendingResponses.insert(std::make_pair(seqno, std::move(callback))); |
241 | 0 | gUnresolvedResponses++; |
242 | 0 | } Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::wr::MemoryReport>(IPC::Message*, void*, std::__1::function<void (mozilla::wr::MemoryReport&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild> >(IPC::Message*, void*, std::__1::function<void (mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::ipc::FileDescriptor>(IPC::Message*, void*, std::__1::function<void (mozilla::ipc::FileDescriptor&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::dom::CreatedWindowInfo>(IPC::Message*, void*, std::__1::function<void (mozilla::dom::CreatedWindowInfo&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<bool>(IPC::Message*, void*, std::__1::function<void (bool&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<RefPtr<nsIInputStream> >(IPC::Message*, void*, std::__1::function<void (RefPtr<nsIInputStream>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::ipc::Shmem>(IPC::Message*, void*, std::__1::function<void (mozilla::ipc::Shmem&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::Tuple<bool, nsTString<char16_t> > >(IPC::Message*, void*, std::__1::function<void (mozilla::Tuple<bool, nsTString<char16_t> >&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult>(IPC::Message*, void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult>(IPC::Message*, void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::Tuple<bool, mozilla::CopyableErrorResult> >(IPC::Message*, void*, std::__1::function<void (mozilla::Tuple<bool, mozilla::CopyableErrorResult>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::widget::IMENotificationRequests>(IPC::Message*, void*, std::__1::function<void (mozilla::widget::IMENotificationRequests&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&) |
243 | | |
244 | | bool SendBuildIDsMatchMessage(const char* aParentBuildI); |
245 | 0 | bool DoBuildIDsMatch() { return mBuildIDsConfirmedMatch; } |
246 | | |
247 | | // Asynchronously deliver a message back to this side of the |
248 | | // channel |
249 | | bool Echo(Message* aMsg); |
250 | | |
251 | | // Synchronously send |msg| (i.e., wait for |reply|) |
252 | | bool Send(Message* aMsg, Message* aReply); |
253 | | |
254 | | // Make an Interrupt call to the other side of the channel |
255 | | bool Call(Message* aMsg, Message* aReply); |
256 | | |
257 | | // Wait until a message is received |
258 | | bool WaitForIncomingMessage(); |
259 | | |
260 | | bool CanSend() const; |
261 | | |
262 | | // Remove and return a callback that needs reply |
263 | | UniquePtr<UntypedCallbackHolder> PopCallback(const Message& aMsg); |
264 | | |
265 | | // Used to reject and remove pending responses owned by the given |
266 | | // actor when it's about to be destroyed. |
267 | | void RejectPendingResponsesForActor(ActorIdType aActorId); |
268 | | |
269 | | // If sending a sync message returns an error, this function gives a more |
270 | | // descriptive error message. |
271 | 0 | SyncSendError LastSendError() const { |
272 | 0 | AssertWorkerThread(); |
273 | 0 | return mLastSendError; |
274 | 0 | } |
275 | | |
276 | | // Currently only for debugging purposes, doesn't aquire mMonitor. |
277 | 0 | ChannelState GetChannelState__TotallyRacy() const { |
278 | 0 | return mChannelState; |
279 | 0 | } |
280 | | |
281 | | void SetReplyTimeoutMs(int32_t aTimeoutMs); |
282 | | |
283 | 0 | bool IsOnCxxStack() const { |
284 | 0 | return !mCxxStackFrames.empty(); |
285 | 0 | } |
286 | | |
287 | | bool IsInTransaction() const; |
288 | | void CancelCurrentTransaction(); |
289 | | |
290 | | // Force all calls to Send to defer actually sending messages. This will |
291 | | // cause sync messages to block until another thread calls |
292 | | // StopPostponingSends. |
293 | | // |
294 | | // This must be called from the worker thread. |
295 | | void BeginPostponingSends(); |
296 | | |
297 | | // Stop postponing sent messages, and immediately flush all postponed |
298 | | // messages to the link. This may be called from any thread. |
299 | | // |
300 | | // Note that there are no ordering guarantees between two different |
301 | | // MessageChannels. If channel B sends a message, then stops postponing |
302 | | // channel A, messages from A may arrive before B. The easiest way to order |
303 | | // this, if needed, is to make B send a sync message. |
304 | | void StopPostponingSends(); |
305 | | |
306 | | /** |
307 | | * This function is used by hang annotation code to determine which IPDL |
308 | | * actor is highest in the call stack at the time of the hang. It should |
309 | | * be called from the main thread when a sync or intr message is about to |
310 | | * be sent. |
311 | | */ |
312 | | int32_t GetTopmostMessageRoutingId() const; |
313 | | |
314 | | // Unsound_IsClosed and Unsound_NumQueuedMessages are safe to call from any |
315 | | // thread, but they make no guarantees about whether you'll get an |
316 | | // up-to-date value; the values are written on one thread and read without |
317 | | // locking, on potentially different threads. Thus you should only use |
318 | | // them when you don't particularly care about getting a recent value (e.g. |
319 | | // in a memory report). |
320 | 0 | bool Unsound_IsClosed() const { |
321 | 0 | return mLink ? mLink->Unsound_IsClosed() : true; |
322 | 0 | } |
323 | 0 | uint32_t Unsound_NumQueuedMessages() const { |
324 | 0 | return mLink ? mLink->Unsound_NumQueuedMessages() : 0; |
325 | 0 | } |
326 | | |
327 | 0 | static bool IsPumpingMessages() { |
328 | 0 | return sIsPumpingMessages; |
329 | 0 | } |
330 | 0 | static void SetIsPumpingMessages(bool aIsPumping) { |
331 | 0 | sIsPumpingMessages = aIsPumping; |
332 | 0 | } |
333 | | |
334 | 0 | void SetInKillHardShutdown() { |
335 | 0 | mInKillHardShutdown = true; |
336 | 0 | } |
337 | | |
338 | | #ifdef OS_WIN |
339 | | struct MOZ_STACK_CLASS SyncStackFrame |
340 | | { |
341 | | SyncStackFrame(MessageChannel* channel, bool interrupt); |
342 | | ~SyncStackFrame(); |
343 | | |
344 | | bool mInterrupt; |
345 | | bool mSpinNestedEvents; |
346 | | bool mListenerNotified; |
347 | | MessageChannel* mChannel; |
348 | | |
349 | | // The previous stack frame for this channel. |
350 | | SyncStackFrame* mPrev; |
351 | | |
352 | | // The previous stack frame on any channel. |
353 | | SyncStackFrame* mStaticPrev; |
354 | | }; |
355 | | friend struct MessageChannel::SyncStackFrame; |
356 | | |
357 | | static bool IsSpinLoopActive() { |
358 | | for (SyncStackFrame* frame = sStaticTopFrame; frame; frame = frame->mPrev) { |
359 | | if (frame->mSpinNestedEvents) |
360 | | return true; |
361 | | } |
362 | | return false; |
363 | | } |
364 | | |
365 | | protected: |
366 | | // The deepest sync stack frame for this channel. |
367 | | SyncStackFrame* mTopFrame; |
368 | | |
369 | | bool mIsSyncWaitingOnNonMainThread; |
370 | | |
371 | | // The deepest sync stack frame on any channel. |
372 | | static SyncStackFrame* sStaticTopFrame; |
373 | | |
374 | | public: |
375 | | void ProcessNativeEventsInInterruptCall(); |
376 | | static void NotifyGeckoEventDispatch(); |
377 | | |
378 | | private: |
379 | | void SpinInternalEventLoop(); |
380 | | #if defined(ACCESSIBILITY) |
381 | | bool WaitForSyncNotifyWithA11yReentry(); |
382 | | #endif // defined(ACCESSIBILITY) |
383 | | #endif // defined(OS_WIN) |
384 | | |
385 | | private: |
386 | | void CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide); |
387 | | void OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide); |
388 | | |
389 | | void PostErrorNotifyTask(); |
390 | | void OnNotifyMaybeChannelError(); |
391 | | void ReportConnectionError(const char* aChannelName, Message* aMsg = nullptr) const; |
392 | | void ReportMessageRouteError(const char* channelName) const; |
393 | | bool MaybeHandleError(Result code, const Message& aMsg, const char* channelName); |
394 | | |
395 | | void Clear(); |
396 | | |
397 | | // Send OnChannelConnected notification to listeners. |
398 | | void DispatchOnChannelConnected(); |
399 | | |
400 | | bool InterruptEventOccurred(); |
401 | | bool HasPendingEvents(); |
402 | | |
403 | | void ProcessPendingRequests(AutoEnterTransaction& aTransaction); |
404 | | bool ProcessPendingRequest(Message &&aUrgent); |
405 | | |
406 | | void MaybeUndeferIncall(); |
407 | | void EnqueuePendingMessages(); |
408 | | |
409 | | // Dispatches an incoming message to its appropriate handler. |
410 | | void DispatchMessage(Message &&aMsg); |
411 | | |
412 | | // DispatchMessage will route to one of these functions depending on the |
413 | | // protocol type of the message. |
414 | | void DispatchSyncMessage(const Message &aMsg, Message*& aReply); |
415 | | void DispatchUrgentMessage(const Message &aMsg); |
416 | | void DispatchAsyncMessage(const Message &aMsg); |
417 | | void DispatchRPCMessage(const Message &aMsg); |
418 | | void DispatchInterruptMessage(Message &&aMsg, size_t aStackDepth); |
419 | | |
420 | | // Return true if the wait ended because a notification was received. |
421 | | // |
422 | | // Return false if the time elapsed from when we started the process of |
423 | | // waiting until afterwards exceeded the currently allotted timeout. |
424 | | // That *DOES NOT* mean false => "no event" (== timeout); there are many |
425 | | // circumstances that could cause the measured elapsed time to exceed the |
426 | | // timeout EVEN WHEN we were notified. |
427 | | // |
428 | | // So in sum: true is a meaningful return value; false isn't, |
429 | | // necessarily. |
430 | | bool WaitForSyncNotify(bool aHandleWindowsMessages); |
431 | | bool WaitForInterruptNotify(); |
432 | | |
433 | | bool WaitResponse(bool aWaitTimedOut); |
434 | | |
435 | | bool ShouldContinueFromTimeout(); |
436 | | |
437 | | void EndTimeout(); |
438 | | void CancelTransaction(int transaction); |
439 | | |
440 | | void RepostAllMessages(); |
441 | | |
442 | | // The "remote view of stack depth" can be different than the |
443 | | // actual stack depth when there are out-of-turn replies. When we |
444 | | // receive one, our actual Interrupt stack depth doesn't decrease, but |
445 | | // the other side (that sent the reply) thinks it has. So, the |
446 | | // "view" returned here is |stackDepth| minus the number of |
447 | | // out-of-turn replies. |
448 | | // |
449 | | // Only called from the worker thread. |
450 | 0 | size_t RemoteViewOfStackDepth(size_t stackDepth) const { |
451 | 0 | AssertWorkerThread(); |
452 | 0 | return stackDepth - mOutOfTurnReplies.size(); |
453 | 0 | } |
454 | | |
455 | 0 | int32_t NextSeqno() { |
456 | 0 | AssertWorkerThread(); |
457 | 0 | return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno; |
458 | 0 | } |
459 | | |
460 | | // This helper class manages mCxxStackDepth on behalf of MessageChannel. |
461 | | // When the stack depth is incremented from zero to non-zero, it invokes |
462 | | // a callback, and similarly for when the depth goes from non-zero to zero. |
463 | | void EnteredCxxStack(); |
464 | | void ExitedCxxStack(); |
465 | | |
466 | | void EnteredCall(); |
467 | | void ExitedCall(); |
468 | | |
469 | | void EnteredSyncSend(); |
470 | | void ExitedSyncSend(); |
471 | | |
472 | | void DebugAbort(const char* file, int line, const char* cond, |
473 | | const char* why, |
474 | | bool reply=false); |
475 | | |
476 | | // This method is only safe to call on the worker thread, or in a |
477 | | // debugger with all threads paused. |
478 | | void DumpInterruptStack(const char* const pfx="") const; |
479 | | |
480 | | private: |
481 | | // Called from both threads |
482 | 0 | size_t InterruptStackDepth() const { |
483 | 0 | mMonitor->AssertCurrentThreadOwns(); |
484 | 0 | return mInterruptStack.size(); |
485 | 0 | } |
486 | | |
487 | 0 | bool AwaitingInterruptReply() const { |
488 | 0 | mMonitor->AssertCurrentThreadOwns(); |
489 | 0 | return !mInterruptStack.empty(); |
490 | 0 | } |
491 | 0 | bool AwaitingIncomingMessage() const { |
492 | 0 | mMonitor->AssertCurrentThreadOwns(); |
493 | 0 | return mIsWaitingForIncoming; |
494 | 0 | } |
495 | | |
496 | | class MOZ_STACK_CLASS AutoEnterWaitForIncoming |
497 | | { |
498 | | public: |
499 | | explicit AutoEnterWaitForIncoming(MessageChannel& aChannel) |
500 | | : mChannel(aChannel) |
501 | 0 | { |
502 | 0 | aChannel.mMonitor->AssertCurrentThreadOwns(); |
503 | 0 | aChannel.mIsWaitingForIncoming = true; |
504 | 0 | } |
505 | | |
506 | | ~AutoEnterWaitForIncoming() |
507 | 0 | { |
508 | 0 | mChannel.mIsWaitingForIncoming = false; |
509 | 0 | } |
510 | | |
511 | | private: |
512 | | MessageChannel& mChannel; |
513 | | }; |
514 | | friend class AutoEnterWaitForIncoming; |
515 | | |
516 | | // Returns true if we're dispatching an async message's callback. |
517 | 0 | bool DispatchingAsyncMessage() const { |
518 | 0 | AssertWorkerThread(); |
519 | 0 | return mDispatchingAsyncMessage; |
520 | 0 | } |
521 | | |
522 | 0 | int DispatchingAsyncMessageNestedLevel() const { |
523 | 0 | AssertWorkerThread(); |
524 | 0 | return mDispatchingAsyncMessageNestedLevel; |
525 | 0 | } |
526 | | |
527 | | bool Connected() const; |
528 | | |
529 | | private: |
530 | | // Executed on the IO thread. |
531 | | void NotifyWorkerThread(); |
532 | | |
533 | | // Return true if |aMsg| is a special message targeted at the IO |
534 | | // thread, in which case it shouldn't be delivered to the worker. |
535 | | bool MaybeInterceptSpecialIOMessage(const Message& aMsg); |
536 | | |
537 | | void OnChannelConnected(int32_t peer_id); |
538 | | |
539 | | // Tell the IO thread to close the channel and wait for it to ACK. |
540 | | void SynchronouslyClose(); |
541 | | |
542 | | // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true. |
543 | | // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false, |
544 | | // depending on context. |
545 | | static bool IsAlwaysDeferred(const Message& aMsg); |
546 | | |
547 | | // Helper for sending a message via the link. This should only be used for |
548 | | // non-special messages that might have to be postponed. |
549 | | void SendMessageToLink(Message* aMsg); |
550 | | |
551 | | bool WasTransactionCanceled(int transaction); |
552 | | bool ShouldDeferMessage(const Message& aMsg); |
553 | | bool ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDepth); |
554 | | void OnMessageReceivedFromLink(Message&& aMsg); |
555 | | void OnChannelErrorFromLink(); |
556 | | |
557 | | private: |
558 | | // Run on the not current thread. |
559 | | void NotifyChannelClosed(); |
560 | | void NotifyMaybeChannelError(); |
561 | | |
562 | | private: |
563 | | // Can be run on either thread |
564 | | void AssertWorkerThread() const |
565 | 0 | { |
566 | 0 | MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet"); |
567 | 0 | MOZ_RELEASE_ASSERT(mWorkerThread == GetCurrentVirtualThread(), |
568 | 0 | "not on worker thread!"); |
569 | 0 | } |
570 | | |
571 | | // The "link" thread is either the I/O thread (ProcessLink) or the |
572 | | // other actor's work thread (ThreadLink). In either case, it is |
573 | | // NOT our worker thread. |
574 | | void AssertLinkThread() const |
575 | 0 | { |
576 | 0 | MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet"); |
577 | 0 | MOZ_RELEASE_ASSERT(mWorkerThread != GetCurrentVirtualThread(), |
578 | 0 | "on worker thread but should not be!"); |
579 | 0 | } |
580 | | |
581 | | private: |
582 | | class MessageTask : |
583 | | public CancelableRunnable, |
584 | | public LinkedListElement<RefPtr<MessageTask>>, |
585 | | public nsIRunnablePriority, |
586 | | public nsILabelableRunnable |
587 | | { |
588 | | public: |
589 | | explicit MessageTask(MessageChannel* aChannel, Message&& aMessage); |
590 | | |
591 | | NS_DECL_ISUPPORTS_INHERITED |
592 | | |
593 | | NS_IMETHOD Run() override; |
594 | | nsresult Cancel() override; |
595 | | NS_IMETHOD GetPriority(uint32_t* aPriority) override; |
596 | | void Post(); |
597 | | void Clear(); |
598 | | |
599 | 0 | bool IsScheduled() const { return mScheduled; } |
600 | | |
601 | 0 | Message& Msg() { return mMessage; } |
602 | 0 | const Message& Msg() const { return mMessage; } |
603 | | |
604 | | bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override; |
605 | | |
606 | | private: |
607 | | MessageTask() = delete; |
608 | | MessageTask(const MessageTask&) = delete; |
609 | 0 | ~MessageTask() {} |
610 | | |
611 | | MessageChannel* mChannel; |
612 | | Message mMessage; |
613 | | bool mScheduled : 1; |
614 | | }; |
615 | | |
616 | | bool ShouldRunMessage(const Message& aMsg); |
617 | | void RunMessage(MessageTask& aTask); |
618 | | |
619 | | typedef LinkedList<RefPtr<MessageTask>> MessageQueue; |
620 | | typedef std::map<size_t, Message> MessageMap; |
621 | | typedef std::map<size_t, UniquePtr<UntypedCallbackHolder>> CallbackMap; |
622 | | typedef IPC::Message::msgid_t msgid_t; |
623 | | |
624 | | void WillDestroyCurrentMessageLoop() override; |
625 | | |
626 | | private: |
627 | | // This will be a string literal, so lifetime is not an issue. |
628 | | const char* mName; |
629 | | |
630 | | // Based on presumption the listener owns and overlives the channel, |
631 | | // this is never nullified. |
632 | | IToplevelProtocol* mListener; |
633 | | ChannelState mChannelState; |
634 | | RefPtr<RefCountedMonitor> mMonitor; |
635 | | Side mSide; |
636 | | bool mIsCrossProcess; |
637 | | MessageLink* mLink; |
638 | | MessageLoop* mWorkerLoop; // thread where work is done |
639 | | RefPtr<CancelableRunnable> mChannelErrorTask; // NotifyMaybeChannelError runnable |
640 | | |
641 | | // Thread we are allowed to send and receive on. This persists even after |
642 | | // mWorkerLoop is cleared during channel shutdown. |
643 | | PRThread* mWorkerThread; |
644 | | |
645 | | // Timeout periods are broken up in two to prevent system suspension from |
646 | | // triggering an abort. This method (called by WaitForEvent with a 'did |
647 | | // timeout' flag) decides if we should wait again for half of mTimeoutMs |
648 | | // or give up. |
649 | | int32_t mTimeoutMs; |
650 | | bool mInTimeoutSecondHalf; |
651 | | |
652 | | // Worker-thread only; sequence numbers for messages that require |
653 | | // replies. |
654 | | int32_t mNextSeqno; |
655 | | |
656 | | static bool sIsPumpingMessages; |
657 | | |
658 | | // If ::Send returns false, this gives a more descriptive error. |
659 | | SyncSendError mLastSendError; |
660 | | |
661 | | template<class T> |
662 | | class AutoSetValue { |
663 | | public: |
664 | | explicit AutoSetValue(T &var, const T &newValue) |
665 | | : mVar(var), mPrev(var), mNew(newValue) |
666 | 0 | { |
667 | 0 | mVar = newValue; |
668 | 0 | } Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<mozilla::ipc::MessageChannel*>::AutoSetValue(mozilla::ipc::MessageChannel*&, mozilla::ipc::MessageChannel* const&) Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<bool>::AutoSetValue(bool&, bool const&) Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<int>::AutoSetValue(int&, int const&) |
669 | 0 | ~AutoSetValue() { |
670 | 0 | // The value may have been zeroed if the transaction was |
671 | 0 | // canceled. In that case we shouldn't return it to its previous |
672 | 0 | // value. |
673 | 0 | if (mVar == mNew) { |
674 | 0 | mVar = mPrev; |
675 | 0 | } |
676 | 0 | } Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<mozilla::ipc::MessageChannel*>::~AutoSetValue() Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<bool>::~AutoSetValue() Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<int>::~AutoSetValue() |
677 | | private: |
678 | | T& mVar; |
679 | | T mPrev; |
680 | | T mNew; |
681 | | }; |
682 | | |
683 | | bool mDispatchingAsyncMessage; |
684 | | int mDispatchingAsyncMessageNestedLevel; |
685 | | |
686 | | // When we send an urgent request from the parent process, we could race |
687 | | // with an RPC message that was issued by the child beforehand. In this |
688 | | // case, if the parent were to wake up while waiting for the urgent reply, |
689 | | // and process the RPC, it could send an additional urgent message. The |
690 | | // child would wake up to process the urgent message (as it always will), |
691 | | // then send a reply, which could be received by the parent out-of-order |
692 | | // with respect to the first urgent reply. |
693 | | // |
694 | | // To address this problem, urgent or RPC requests are associated with a |
695 | | // "transaction". Whenever one side of the channel wishes to start a |
696 | | // chain of RPC/urgent messages, it allocates a new transaction ID. Any |
697 | | // messages the parent receives, not apart of this transaction, are |
698 | | // deferred. When issuing RPC/urgent requests on top of a started |
699 | | // transaction, the initiating transaction ID is used. |
700 | | // |
701 | | // To ensure IDs are unique, we use sequence numbers for transaction IDs, |
702 | | // which grow in opposite directions from child to parent. |
703 | | |
704 | | friend class AutoEnterTransaction; |
705 | | AutoEnterTransaction *mTransactionStack; |
706 | | |
707 | | int32_t CurrentNestedInsideSyncTransaction() const; |
708 | | |
709 | | bool AwaitingSyncReply() const; |
710 | | int AwaitingSyncReplyNestedLevel() const; |
711 | | |
712 | | bool DispatchingSyncMessage() const; |
713 | | int DispatchingSyncMessageNestedLevel() const; |
714 | | |
715 | | #ifdef DEBUG |
716 | | void AssertMaybeDeferredCountCorrect(); |
717 | | #else |
718 | 0 | void AssertMaybeDeferredCountCorrect() {} |
719 | | #endif |
720 | | |
721 | | // If a sync message times out, we store its sequence number here. Any |
722 | | // future sync messages will fail immediately. Once the reply for original |
723 | | // sync message is received, we allow sync messages again. |
724 | | // |
725 | | // When a message times out, nothing is done to inform the other side. The |
726 | | // other side will eventually dispatch the message and send a reply. Our |
727 | | // side is responsible for replying to all sync messages sent by the other |
728 | | // side when it dispatches the timed out message. The response is always an |
729 | | // error. |
730 | | // |
731 | | // A message is only timed out if it initiated a transaction. This avoids |
732 | | // hitting a lot of corner cases with message nesting that we don't really |
733 | | // care about. |
734 | | int32_t mTimedOutMessageSeqno; |
735 | | int mTimedOutMessageNestedLevel; |
736 | | |
737 | | // Queue of all incoming messages. |
738 | | // |
739 | | // If both this side and the other side are functioning correctly, the queue |
740 | | // can only be in certain configurations. Let |
741 | | // |
742 | | // |A<| be an async in-message, |
743 | | // |S<| be a sync in-message, |
744 | | // |C<| be an Interrupt in-call, |
745 | | // |R<| be an Interrupt reply. |
746 | | // |
747 | | // The queue can only match this configuration |
748 | | // |
749 | | // A<* (S< | C< | R< (?{mInterruptStack.size() == 1} A<* (S< | C<))) |
750 | | // |
751 | | // The other side can send as many async messages |A<*| as it wants before |
752 | | // sending us a blocking message. |
753 | | // |
754 | | // The first case is |S<|, a sync in-msg. The other side must be blocked, |
755 | | // and thus can't send us any more messages until we process the sync |
756 | | // in-msg. |
757 | | // |
758 | | // The second case is |C<|, an Interrupt in-call; the other side must be blocked. |
759 | | // (There's a subtlety here: this in-call might have raced with an |
760 | | // out-call, but we detect that with the mechanism below, |
761 | | // |mRemoteStackDepth|, and races don't matter to the queue.) |
762 | | // |
763 | | // Final case, the other side replied to our most recent out-call |R<|. |
764 | | // If that was the *only* out-call on our stack, |?{mInterruptStack.size() == 1}|, |
765 | | // then other side "finished with us," and went back to its own business. |
766 | | // That business might have included sending any number of async message |
767 | | // |A<*| until sending a blocking message |(S< | C<)|. If we had more than |
768 | | // one Interrupt call on our stack, the other side *better* not have sent us |
769 | | // another blocking message, because it's blocked on a reply from us. |
770 | | // |
771 | | MessageQueue mPending; |
772 | | |
773 | | // The number of messages in mPending for which IsAlwaysDeferred is false |
774 | | // (i.e., the number of messages that might not be deferred, depending on |
775 | | // context). |
776 | | size_t mMaybeDeferredPendingCount; |
777 | | |
778 | | // Stack of all the out-calls on which this channel is awaiting responses. |
779 | | // Each stack refers to a different protocol and the stacks are mutually |
780 | | // exclusive: multiple outcalls of the same kind cannot be initiated while |
781 | | // another is active. |
782 | | std::stack<MessageInfo> mInterruptStack; |
783 | | |
784 | | // This is what we think the Interrupt stack depth is on the "other side" of this |
785 | | // Interrupt channel. We maintain this variable so that we can detect racy Interrupt |
786 | | // calls. With each Interrupt out-call sent, we send along what *we* think the |
787 | | // stack depth of the remote side is *before* it will receive the Interrupt call. |
788 | | // |
789 | | // After sending the out-call, our stack depth is "incremented" by pushing |
790 | | // that pending message onto mPending. |
791 | | // |
792 | | // Then when processing an in-call |c|, it must be true that |
793 | | // |
794 | | // mInterruptStack.size() == c.remoteDepth |
795 | | // |
796 | | // I.e., my depth is actually the same as what the other side thought it |
797 | | // was when it sent in-call |c|. If this fails to hold, we have detected |
798 | | // racy Interrupt calls. |
799 | | // |
800 | | // We then increment mRemoteStackDepth *just before* processing the |
801 | | // in-call, since we know the other side is waiting on it, and decrement |
802 | | // it *just after* finishing processing that in-call, since our response |
803 | | // will pop the top of the other side's |mPending|. |
804 | | // |
805 | | // One nice aspect of this race detection is that it is symmetric; if one |
806 | | // side detects a race, then the other side must also detect the same race. |
807 | | size_t mRemoteStackDepthGuess; |
808 | | |
809 | | // Approximation of code frames on the C++ stack. It can only be |
810 | | // interpreted as the implication: |
811 | | // |
812 | | // !mCxxStackFrames.empty() => MessageChannel code on C++ stack |
813 | | // |
814 | | // This member is only accessed on the worker thread, and so is not |
815 | | // protected by mMonitor. It is managed exclusively by the helper |
816 | | // |class CxxStackFrame|. |
817 | | mozilla::Vector<InterruptFrame> mCxxStackFrames; |
818 | | |
819 | | // Did we process an Interrupt out-call during this stack? Only meaningful in |
820 | | // ExitedCxxStack(), from which this variable is reset. |
821 | | bool mSawInterruptOutMsg; |
822 | | |
823 | | // Are we waiting on this channel for an incoming message? This is used |
824 | | // to implement WaitForIncomingMessage(). Must only be accessed while owning |
825 | | // mMonitor. |
826 | | bool mIsWaitingForIncoming; |
827 | | |
828 | | // Map of replies received "out of turn", because of Interrupt |
829 | | // in-calls racing with replies to outstanding in-calls. See |
830 | | // https://bugzilla.mozilla.org/show_bug.cgi?id=521929. |
831 | | MessageMap mOutOfTurnReplies; |
832 | | |
833 | | // Map of async Callbacks that are still waiting replies. |
834 | | CallbackMap mPendingResponses; |
835 | | |
836 | | // Stack of Interrupt in-calls that were deferred because of race |
837 | | // conditions. |
838 | | std::stack<Message> mDeferred; |
839 | | |
840 | | #ifdef OS_WIN |
841 | | HANDLE mEvent; |
842 | | #endif |
843 | | |
844 | | // Should the channel abort the process from the I/O thread when |
845 | | // a channel error occurs? |
846 | | bool mAbortOnError; |
847 | | |
848 | | // True if the listener has already been notified of a channel close or |
849 | | // error. |
850 | | bool mNotifiedChannelDone; |
851 | | |
852 | | // See SetChannelFlags |
853 | | ChannelFlags mFlags; |
854 | | |
855 | | // Task and state used to asynchronously notify channel has been connected |
856 | | // safely. This is necessary to be able to cancel notification if we are |
857 | | // closed at the same time. |
858 | | RefPtr<CancelableRunnable> mOnChannelConnectedTask; |
859 | | bool mPeerPidSet; |
860 | | int32_t mPeerPid; |
861 | | |
862 | | // Channels can enter messages are not sent immediately; instead, they are |
863 | | // held in a queue until another thread deems it is safe to send them. |
864 | | bool mIsPostponingSends; |
865 | | std::vector<UniquePtr<Message>> mPostponedSends; |
866 | | |
867 | | bool mInKillHardShutdown; |
868 | | |
869 | | bool mBuildIDsConfirmedMatch; |
870 | | }; |
871 | | |
872 | | void |
873 | | CancelCPOWs(); |
874 | | |
875 | | } // namespace ipc |
876 | | } // namespace mozilla |
877 | | |
878 | | namespace IPC { |
879 | | template <> |
880 | | struct ParamTraits<mozilla::ipc::ResponseRejectReason> |
881 | | : public ContiguousEnumSerializer<mozilla::ipc::ResponseRejectReason, |
882 | | mozilla::ipc::ResponseRejectReason::SendError, |
883 | | mozilla::ipc::ResponseRejectReason::EndGuard_> |
884 | | { }; |
885 | | } // namespace IPC |
886 | | |
887 | | #endif // ifndef ipc_glue_MessageChannel_h |