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>
22 ChannelEvent() { MOZ_COUNT_CTOR(ChannelEvent
); }
23 virtual ~ChannelEvent() { MOZ_COUNT_DTOR(ChannelEvent
); }
24 virtual void Run() = 0;
27 // Workaround for Necko re-entrancy dangers. We buffer IPDL messages in a
28 // queue if still dispatching previous one(s) to listeners/observers.
29 // Otherwise synchronous XMLHttpRequests and/or other code that spins the
30 // event loop (ex: IPDL rpc) could cause listener->OnDataAvailable (for
31 // instance) to be dispatched and called before mListener->OnStartRequest has
34 class AutoEventEnqueuerBase
;
36 class ChannelEventQueue
39 ChannelEventQueue(nsISupports
*owner
)
45 ~ChannelEventQueue() {}
47 // Checks to determine if an IPDL-generated channel event can be processed
48 // immediately, or needs to be queued using Enqueue().
49 inline bool ShouldEnqueue();
51 // Puts IPDL-generated channel event into queue, to be run later
52 // automatically when EndForcedQueueing and/or Resume is called.
53 inline void Enqueue(ChannelEvent
* callback
);
55 // After StartForcedQueueing is called, ShouldEnqueue() will return true and
56 // no events will be run/flushed until EndForcedQueueing is called.
57 // - Note: queueing may still be required after EndForcedQueueing() (if the
58 // queue is suspended, etc): always call ShouldEnqueue() to determine
59 // whether queueing is needed.
60 inline void StartForcedQueueing();
61 inline void EndForcedQueueing();
63 // Suspend/resume event queue. ShouldEnqueue() will return true and no events
64 // will be run/flushed until resume is called. These should be called when
65 // the channel owning the event queue is suspended/resumed.
66 // - Note: these suspend/resume functions are NOT meant to be called
67 // recursively: call them only at initial suspend, and actual resume).
68 // - Note: Resume flushes the queue and invokes any pending callbacks
69 // immediately--caller must arrange any needed asynchronicity vis a vis
70 // the channel's own Resume() method.
71 inline void Suspend();
75 inline void MaybeFlushQueue();
78 nsTArray
<nsAutoPtr
<ChannelEvent
> > mEventQueue
;
84 // Keep ptr to avoid refcount cycle: only grab ref during flushing.
87 friend class AutoEventEnqueuer
;
91 ChannelEventQueue::ShouldEnqueue()
93 bool answer
= mForced
|| mSuspended
|| mFlushing
;
95 NS_ABORT_IF_FALSE(answer
== true || mEventQueue
.IsEmpty(),
96 "Should always enqueue if ChannelEventQueue not empty");
102 ChannelEventQueue::Enqueue(ChannelEvent
* callback
)
104 mEventQueue
.AppendElement(callback
);
108 ChannelEventQueue::StartForcedQueueing()
114 ChannelEventQueue::EndForcedQueueing()
121 ChannelEventQueue::Suspend()
123 NS_ABORT_IF_FALSE(!mSuspended
,
124 "ChannelEventQueue::Suspend called recursively");
130 ChannelEventQueue::Resume()
132 NS_ABORT_IF_FALSE(mSuspended
,
133 "ChannelEventQueue::Resume called when not suspended!");
140 ChannelEventQueue::MaybeFlushQueue()
142 // Don't flush if forced queuing on, we're already being flushed, or
143 // suspended, or there's nothing to flush
144 if (!mForced
&& !mFlushing
&& !mSuspended
&& !mEventQueue
.IsEmpty())
148 // Ensures that ShouldEnqueue() will be true during its lifetime (letting
149 // caller know incoming IPDL msgs should be queued). Flushes the queue when it
150 // goes out of scope.
151 class AutoEventEnqueuer
154 AutoEventEnqueuer(ChannelEventQueue
&queue
) : mEventQueue(queue
) {
155 mEventQueue
.StartForcedQueueing();
157 ~AutoEventEnqueuer() {
158 mEventQueue
.EndForcedQueueing();
161 ChannelEventQueue
&mEventQueue
;