1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at:
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Code.
19 * The Initial Developer of the Original Code is
20 * The Mozilla Foundation
21 * Portions created by the Initial Developer are Copyright (C) 2010
22 * the Initial Developer. All Rights Reserved.
25 * Josh Matthews <josh@joshmatthews.net> (initial developer)
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef mozilla_net_ChannelEventQueue_h
42 #define mozilla_net_ChannelEventQueue_h
50 ChannelEvent() { MOZ_COUNT_CTOR(ChannelEvent
); }
51 virtual ~ChannelEvent() { MOZ_COUNT_DTOR(ChannelEvent
); }
52 virtual void Run() = 0;
55 // Workaround for Necko re-entrancy dangers. We buffer IPDL messages in a
56 // queue if still dispatching previous one(s) to listeners/observers.
57 // Otherwise synchronous XMLHttpRequests and/or other code that spins the
58 // event loop (ex: IPDL rpc) could cause listener->OnDataAvailable (for
59 // instance) to be called before mListener->OnStartRequest has completed.
61 template<class T
> class AutoEventEnqueuerBase
;
64 class ChannelEventQueue
67 ChannelEventQueue(T
* self
) : mQueuePhase(PHASE_UNQUEUED
)
69 ~ChannelEventQueue() {}
72 void BeginEventQueueing();
73 void EndEventQueueing();
74 void EnqueueEvent(ChannelEvent
* callback
);
76 void FlushEventQueue();
78 nsTArray
<nsAutoPtr
<ChannelEvent
> > mEventQueue
;
82 PHASE_FINISHED_QUEUEING
,
86 typedef AutoEventEnqueuerBase
<T
> AutoEventEnqueuer
;
91 friend class AutoEventEnqueuerBase
<T
>;
94 template<class T
> inline void
95 ChannelEventQueue
<T
>::BeginEventQueueing()
97 if (mQueuePhase
!= PHASE_UNQUEUED
)
99 // Store incoming IPDL messages for later.
100 mQueuePhase
= PHASE_QUEUEING
;
103 template<class T
> inline void
104 ChannelEventQueue
<T
>::EndEventQueueing()
106 if (mQueuePhase
!= PHASE_QUEUEING
)
109 mQueuePhase
= PHASE_FINISHED_QUEUEING
;
112 template<class T
> inline bool
113 ChannelEventQueue
<T
>::ShouldEnqueue()
115 return mQueuePhase
!= PHASE_UNQUEUED
|| mSelf
->IsSuspended();
118 template<class T
> inline void
119 ChannelEventQueue
<T
>::EnqueueEvent(ChannelEvent
* callback
)
121 mEventQueue
.AppendElement(callback
);
124 template<class T
> void
125 ChannelEventQueue
<T
>::FlushEventQueue()
127 NS_ABORT_IF_FALSE(mQueuePhase
!= PHASE_UNQUEUED
,
128 "Queue flushing should not occur if PHASE_UNQUEUED");
130 // Queue already being flushed
131 if (mQueuePhase
!= PHASE_FINISHED_QUEUEING
|| mSelf
->IsSuspended())
134 nsRefPtr
<T
> kungFuDeathGrip(mSelf
);
135 if (mEventQueue
.Length() > 0) {
136 // It is possible for new callbacks to be enqueued as we are
137 // flushing the queue, so the queue must not be cleared until
138 // all callbacks have run.
139 mQueuePhase
= PHASE_FLUSHING
;
142 for (i
= 0; i
< mEventQueue
.Length(); i
++) {
143 mEventQueue
[i
]->Run();
144 if (mSelf
->IsSuspended())
148 // We will always want to remove at least one finished callback.
149 if (i
< mEventQueue
.Length())
152 mEventQueue
.RemoveElementsAt(0, i
);
155 if (mSelf
->IsSuspended())
156 mQueuePhase
= PHASE_QUEUEING
;
158 mQueuePhase
= PHASE_UNQUEUED
;
161 // Ensures any incoming IPDL msgs are queued during its lifetime, and flushes
162 // the queue when it goes out of scope.
164 class AutoEventEnqueuerBase
167 AutoEventEnqueuerBase(ChannelEventQueue
<T
>* queue
) : mEventQueue(queue
)
169 mEventQueue
->BeginEventQueueing();
171 ~AutoEventEnqueuerBase()
173 mEventQueue
->EndEventQueueing();
174 mEventQueue
->FlushEventQueue();
177 ChannelEventQueue
<T
> *mEventQueue
;