1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set sw=2 ts=8 et tw=80 :
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/. */
8 #ifndef mozilla_net_ChannelEventQueue_h
9 #define mozilla_net_ChannelEventQueue_h
12 #include <nsAutoPtr.h>
24 ChannelEvent() { MOZ_COUNT_CTOR(ChannelEvent
); }
25 virtual ~ChannelEvent() { MOZ_COUNT_DTOR(ChannelEvent
); }
26 virtual void Run() = 0;
29 // Workaround for Necko re-entrancy dangers. We buffer IPDL messages in a
30 // queue if still dispatching previous one(s) to listeners/observers.
31 // Otherwise synchronous XMLHttpRequests and/or other code that spins the
32 // event loop (ex: IPDL rpc) could cause listener->OnDataAvailable (for
33 // instance) to be dispatched and called before mListener->OnStartRequest has
36 class AutoEventEnqueuerBase
;
38 class ChannelEventQueue MOZ_FINAL
40 NS_INLINE_DECL_REFCOUNTING(ChannelEventQueue
)
43 explicit ChannelEventQueue(nsISupports
*owner
)
50 // Checks to determine if an IPDL-generated channel event can be processed
51 // immediately, or needs to be queued using Enqueue().
52 inline bool ShouldEnqueue();
54 // Puts IPDL-generated channel event into queue, to be run later
55 // automatically when EndForcedQueueing and/or Resume is called.
56 inline void Enqueue(ChannelEvent
* callback
);
58 // After StartForcedQueueing is called, ShouldEnqueue() will return true and
59 // no events will be run/flushed until EndForcedQueueing is called.
60 // - Note: queueing may still be required after EndForcedQueueing() (if the
61 // queue is suspended, etc): always call ShouldEnqueue() to determine
62 // whether queueing is needed.
63 inline void StartForcedQueueing();
64 inline void EndForcedQueueing();
66 // Suspend/resume event queue. ShouldEnqueue() will return true and no events
67 // will be run/flushed until resume is called. These should be called when
68 // the channel owning the event queue is suspended/resumed.
69 inline void Suspend();
70 // Resume flushes the queue asynchronously, i.e. items in queue will be
71 // dispatched in a new event on the current thread.
74 // Retargets delivery of events to the target thread specified.
75 nsresult
RetargetDeliveryTo(nsIEventTarget
* aTargetThread
);
78 // Private destructor, to discourage deletion outside of Release():
83 inline void MaybeFlushQueue();
85 inline void CompleteResume();
87 nsTArray
<nsAutoPtr
<ChannelEvent
> > mEventQueue
;
89 uint32_t mSuspendCount
;
94 // Keep ptr to avoid refcount cycle: only grab ref during flushing.
97 // Target thread for delivery of events.
98 nsCOMPtr
<nsIThread
> mTargetThread
;
100 friend class AutoEventEnqueuer
;
104 ChannelEventQueue::ShouldEnqueue()
106 bool answer
= mForced
|| mSuspended
|| mFlushing
;
108 NS_ABORT_IF_FALSE(answer
== true || mEventQueue
.IsEmpty(),
109 "Should always enqueue if ChannelEventQueue not empty");
115 ChannelEventQueue::Enqueue(ChannelEvent
* callback
)
117 mEventQueue
.AppendElement(callback
);
121 ChannelEventQueue::StartForcedQueueing()
127 ChannelEventQueue::EndForcedQueueing()
134 ChannelEventQueue::Suspend()
141 ChannelEventQueue::CompleteResume()
143 // channel may have been suspended again since Resume fired event to call this.
144 if (!mSuspendCount
) {
145 // we need to remain logically suspended (for purposes of queuing incoming
146 // messages) until this point, else new incoming messages could run before
154 ChannelEventQueue::MaybeFlushQueue()
156 // Don't flush if forced queuing on, we're already being flushed, or
157 // suspended, or there's nothing to flush
158 if (!mForced
&& !mFlushing
&& !mSuspended
&& !mEventQueue
.IsEmpty())
162 // Ensures that ShouldEnqueue() will be true during its lifetime (letting
163 // caller know incoming IPDL msgs should be queued). Flushes the queue when it
164 // goes out of scope.
165 class AutoEventEnqueuer
168 explicit AutoEventEnqueuer(ChannelEventQueue
*queue
) : mEventQueue(queue
) {
169 mEventQueue
->StartForcedQueueing();
171 ~AutoEventEnqueuer() {
172 mEventQueue
->EndForcedQueueing();
175 ChannelEventQueue
* mEventQueue
;