Back to index

lightning-sunbird  0.9+nobinonly
nsEventQueue.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsCOMPtr.h"
00039 #include "nsEventQueue.h"
00040 #include "nsIEventQueueService.h"
00041 #include "nsIThread.h"
00042 #include "nsIEventQueueListener.h"
00043 
00044 #include "nsIServiceManager.h"
00045 #include "nsIObserverService.h"
00046 
00047 #include "nsString.h"
00048 
00049 #include "prlog.h"
00050 
00051 #ifdef NS_DEBUG
00052 #include "prprf.h"
00053 #endif
00054 
00055 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00056 /* found these logs useful in conjunction with netlibStreamEvent logging
00057    from netwerk. */
00058 PRLogModuleInfo* gEventQueueLog = 0;
00059 PRUint32 gEventQueueLogCount = 0;
00060 PRUint32 gEventQueueLogPPCount = 0;
00061 static int gEventQueueLogPPLevel = 0;
00062 static PLEventQueue *gEventQueueLogQueue = 0;
00063 static PRThread *gEventQueueLogThread = 0;
00064 #endif
00065 
00066 // in a real system, these would be members in a header class...
00067 static const char gActivatedNotification[] = "nsIEventQueueActivated";
00068 static const char gDestroyedNotification[] = "nsIEventQueueDestroyed";
00069 
00070 class ListenerCaller {
00071 public:
00072   ListenerCaller(nsIEventQueue* aQueue, nsresult* rv) : mQueue(aQueue)
00073   {
00074     mListener = do_GetService(NS_EVENT_QUEUE_LISTENER_CONTRACTID);
00075     // There might be no listener...  but if so, warn
00076     if (mListener) {
00077       *rv = mListener->WillProcessEvents(mQueue);
00078     } else {
00079       NS_WARNING("No event queue listener?");
00080       *rv = NS_OK;
00081     }
00082   }
00083 
00084   ~ListenerCaller() {
00085     if (mListener) {
00086       mListener->DidProcessEvents(mQueue);
00087     }
00088   }
00089   
00090 private:
00091   nsIEventQueue* mQueue;
00092   nsCOMPtr<nsIEventQueueListener> mListener;
00093 };
00094 
00095 nsEventQueueImpl::nsEventQueueImpl()
00096 {
00097   NS_ADDREF_THIS();
00098   /* The slightly weird ownership model for eventqueues goes like this:
00099 
00100      General:
00101        There's an addref from the factory generally held by whoever asked for
00102      the queue. The queue addrefs itself (right here) and releases itself
00103      after someone calls StopAcceptingEvents() on the queue and when it is
00104      dark and empty (in CheckForDeactivation()).
00105 
00106      Chained queues:
00107 
00108        Eldest queue:
00109          The eldest queue in a chain is held on to by the EventQueueService
00110        in a hash table, so it is possible that the eldest queue may not be
00111        released until the EventQueueService is shutdown.
00112          You may not call StopAcceptingEvents() on this queue until you have
00113        done so on all younger queues.
00114 
00115        General:
00116          Each queue holds a reference to their immediate elder link and a weak
00117        reference to their immediate younger link.  Because you must shut down
00118        queues from youngest to eldest, all the references will be removed.
00119 
00120        It happens something like:
00121          queue->StopAcceptingEvents()
00122          {
00123            CheckForDeactivation()
00124            {
00125              -- hopefully we are able to shutdown now --
00126              Unlink()
00127              {
00128                -- remove the reference we hold to our elder queue  --
00129                -- NULL out our elder queues weak reference to us --
00130              }
00131              RELEASE ourself (to balance the ADDREF here in the constructor)
00132              -- and we should go away. --
00133            }
00134          }
00135 
00136 
00137      Notes:
00138        A dark queue no longer accepts events.  An empty queue simply has no events.
00139   */
00140 
00141 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00142   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00143          ("EventQueue: Created [queue=%lx]",(long)mEventQueue));
00144   ++gEventQueueLogCount;
00145 #endif
00146 
00147   mYoungerQueue = nsnull;
00148   mEventQueue = nsnull;
00149   mAcceptingEvents = PR_TRUE;
00150   mCouldHaveEvents = PR_TRUE;
00151 }
00152 
00153 nsEventQueueImpl::~nsEventQueueImpl()
00154 {
00155   Unlink();
00156 
00157 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00158   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00159          ("EventQueue: Destroyed [queue=%lx]",(long)mEventQueue));
00160   ++gEventQueueLogCount;
00161 #endif
00162 
00163   if (mEventQueue) {
00164     // Perhaps CheckForDeactivation wasn't called...
00165     if (mCouldHaveEvents)
00166       NotifyObservers(gDestroyedNotification);
00167     PL_DestroyEventQueue(mEventQueue);
00168   }
00169 }
00170 
00171 NS_IMETHODIMP
00172 nsEventQueueImpl::Init(PRBool aNative)
00173 {
00174   PRThread *thread = PR_GetCurrentThread();
00175   if (aNative)
00176     mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread);
00177   else
00178     mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread);
00179   if (!mEventQueue)
00180     return NS_ERROR_FAILURE;
00181   NotifyObservers(gActivatedNotification);
00182   return NS_OK;
00183 }
00184 
00185 NS_IMETHODIMP
00186 nsEventQueueImpl::InitFromPRThread(PRThread* thread, PRBool aNative)
00187 {
00188   if (thread == NS_CURRENT_THREAD)
00189   {
00190      thread = PR_GetCurrentThread();
00191   }
00192   else if (thread == NS_UI_THREAD)
00193   {
00194     nsCOMPtr<nsIThread>  mainIThread;
00195     nsresult rv;
00196 
00197     // Get the primordial thread
00198     rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread));
00199     if (NS_FAILED(rv)) return rv;
00200 
00201     rv = mainIThread->GetPRThread(&thread);
00202     if (NS_FAILED(rv)) return rv;
00203   }
00204 
00205   if (aNative)
00206     mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread);
00207   else
00208     mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread);
00209   if (!mEventQueue)
00210     return NS_ERROR_FAILURE;
00211 
00212   NotifyObservers(gActivatedNotification);
00213   return NS_OK;
00214 }
00215 
00216 NS_IMETHODIMP
00217 nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue)
00218 {
00219   mEventQueue = aQueue;
00220   NotifyObservers(gActivatedNotification);
00221   return NS_OK;
00222 }
00223 
00224 /* nsISupports interface implementation... */
00225 NS_IMPL_THREADSAFE_ISUPPORTS3(nsEventQueueImpl,
00226                               nsIEventQueue,
00227                               nsIEventTarget,
00228                               nsPIEventQueueChain)
00229 
00230 /* nsIEventQueue interface implementation... */
00231 
00232 NS_IMETHODIMP
00233 nsEventQueueImpl::StopAcceptingEvents()
00234 {
00235   // this assertion is bogus.  I should be able to shut down the eldest queue,
00236   //    as long as there are no younger children
00237 
00238 
00239   NS_ASSERTION(mElderQueue || !mYoungerQueue, "attempted to disable eldest queue in chain");
00240   mAcceptingEvents = PR_FALSE;
00241   CheckForDeactivation();
00242 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00243   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00244          ("EventQueue: StopAccepting [queue=%lx, accept=%d, could=%d]",
00245          (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
00246   ++gEventQueueLogCount;
00247 #endif
00248   return NS_OK;
00249 }
00250 
00251 // utility funtion to send observers a notification
00252 void
00253 nsEventQueueImpl::NotifyObservers(const char *aTopic)
00254 {
00255   // only send out this notification for native event queues
00256   if (!PL_IsQueueNative(mEventQueue))
00257     return;
00258 
00259   // we should not call out to the observer service from background threads!
00260   NS_ASSERTION(nsIThread::IsMainThread(),
00261                "Native event queues should only be used on the main thread");
00262 
00263   nsresult rv;
00264   nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1", &rv);
00265   if (NS_SUCCEEDED(rv)) {
00266     nsCOMPtr<nsIEventQueue> kungFuDeathGrip(this);
00267     nsCOMPtr<nsISupports> us(do_QueryInterface(kungFuDeathGrip));
00268     os->NotifyObservers(us, aTopic, NULL);
00269   }
00270 }
00271 
00272 void
00273 nsEventQueueImpl::CheckForDeactivation()
00274 {
00275   if (mCouldHaveEvents && !mAcceptingEvents && !PL_EventAvailable(mEventQueue)) {
00276     if (PL_IsQueueOnCurrentThread(mEventQueue)) {
00277       mCouldHaveEvents = PR_FALSE;
00278       NotifyObservers(gDestroyedNotification);
00279       NS_RELEASE_THIS(); // balance ADDREF from the constructor
00280     } else
00281       NS_ERROR("CheckForDeactivation called from wrong thread!");
00282   }
00283 }
00284 
00285 
00286 NS_IMETHODIMP
00287 nsEventQueueImpl::InitEvent(PLEvent* aEvent,
00288                             void* owner,
00289                             PLHandleEventProc handler,
00290                             PLDestroyEventProc destructor)
00291 {
00292   PL_InitEvent(aEvent, owner, handler, destructor);
00293   return NS_OK;
00294 }
00295 
00296 
00297 NS_IMETHODIMP
00298 nsEventQueueImpl::PostEvent(PLEvent* aEvent)
00299 {
00300   if (!mAcceptingEvents) {
00301 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00302     PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00303            ("EventQueue: Punt posted event [queue=%lx, accept=%d, could=%d]",
00304          (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
00305   ++gEventQueueLogCount;
00306 #endif
00307     nsresult rv = NS_ERROR_FAILURE;
00308     NS_ASSERTION(mElderQueue, "event dropped because event chain is dead");
00309     if (mElderQueue) {
00310       nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
00311       if (elder)
00312         rv = elder->PostEvent(aEvent);
00313     }
00314     return rv;
00315   }
00316 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00317   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00318          ("EventQueue: Posting event [queue=%lx]", (long)mEventQueue));
00319   ++gEventQueueLogCount;
00320 #endif
00321   return PL_PostEvent(mEventQueue, aEvent) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
00322 }
00323 
00324 NS_IMETHODIMP
00325 nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent, void** aResult)
00326 {
00327   if (!mAcceptingEvents) {
00328 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00329     PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00330            ("EventQueue: Punt posted synchronous event [queue=%lx, accept=%d, could=%d]",
00331          (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
00332   ++gEventQueueLogCount;
00333 #endif
00334     nsresult rv = NS_ERROR_NO_INTERFACE;
00335     NS_ASSERTION(mElderQueue, "event dropped because event chain is dead");
00336     if (mElderQueue) {
00337       nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
00338       if (elder)
00339         rv = elder->PostSynchronousEvent(aEvent, aResult);
00340       return rv;
00341     }
00342     return NS_ERROR_ABORT;
00343   }
00344 
00345 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00346   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00347          ("EventQueue: Posting synchronous event [queue=%lx]", (long)mEventQueue));
00348   ++gEventQueueLogCount;
00349 #endif
00350   void* result = PL_PostSynchronousEvent(mEventQueue, aEvent);
00351   if (aResult)
00352     *aResult = result;
00353 
00354   return NS_OK;
00355 }
00356 
00357 NS_IMETHODIMP
00358 nsEventQueueImpl::EnterMonitor()
00359 {
00360   PL_ENTER_EVENT_QUEUE_MONITOR(mEventQueue);
00361   return NS_OK;
00362 }
00363 
00364 NS_IMETHODIMP
00365 nsEventQueueImpl::ExitMonitor()
00366 {
00367   PL_EXIT_EVENT_QUEUE_MONITOR(mEventQueue);
00368   return NS_OK;
00369 }
00370 
00371 
00372 NS_IMETHODIMP
00373 nsEventQueueImpl::RevokeEvents(void* owner)
00374 {
00375   nsCOMPtr<nsIEventQueue> youngest;
00376   GetYoungest(getter_AddRefs(youngest));
00377   NS_ASSERTION(youngest, "How could we possibly not have a youngest queue?");
00378   nsCOMPtr<nsPIEventQueueChain> youngestAsChain(do_QueryInterface(youngest));
00379   NS_ASSERTION(youngestAsChain, "RevokeEvents won't work; expect crashes");
00380   return youngestAsChain->RevokeEventsInternal(owner);
00381 }
00382 
00383 
00384 NS_IMETHODIMP
00385 nsEventQueueImpl::GetPLEventQueue(PLEventQueue** aEventQueue)
00386 {
00387   if (!mEventQueue)
00388     return NS_ERROR_NULL_POINTER;
00389 
00390   *aEventQueue = mEventQueue;
00391   return NS_OK;
00392 }
00393 
00394 NS_IMETHODIMP
00395 nsEventQueueImpl::IsOnCurrentThread(PRBool *aResult)
00396 {
00397     *aResult = PL_IsQueueOnCurrentThread( mEventQueue );
00398     return NS_OK;
00399 }
00400 
00401 
00402 NS_IMETHODIMP
00403 nsEventQueueImpl::IsQueueNative(PRBool *aResult)
00404 {
00405   *aResult = PL_IsQueueNative(mEventQueue);
00406   return NS_OK;
00407 }
00408 
00409 NS_IMETHODIMP
00410 nsEventQueueImpl::PendingEvents(PRBool *aResult)
00411 {
00412     *aResult = PL_EventAvailable(mEventQueue);
00413     if (!*aResult && mElderQueue) {
00414         nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
00415         if (elder)
00416             return elder->EventAvailable(*aResult);
00417     }
00418     return NS_OK;
00419 }
00420 
00421 
00422 NS_IMETHODIMP
00423 nsEventQueueImpl::ProcessPendingEvents()
00424 {
00425   PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
00426 
00427   NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
00428 
00429   if (!correctThread)
00430     return NS_ERROR_FAILURE;
00431 
00432   nsresult rv;
00433   ListenerCaller caller(this, &rv);
00434   NS_ENSURE_SUCCESS(rv, rv);
00435   
00436 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00437   ++gEventQueueLogPPLevel;
00438   if ((gEventQueueLogQueue != mEventQueue || gEventQueueLogThread != PR_GetCurrentThread() ||
00439        gEventQueueLogCount != gEventQueueLogPPCount) && gEventQueueLogPPLevel == 1) {
00440     PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00441            ("EventQueue: Process pending [queue=%lx, accept=%d, could=%d]",
00442            (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
00443     gEventQueueLogPPCount = ++gEventQueueLogCount;
00444     gEventQueueLogQueue = mEventQueue;
00445     gEventQueueLogThread = PR_GetCurrentThread();
00446   }
00447 #endif
00448   PL_ProcessPendingEvents(mEventQueue);
00449 
00450   // if we're no longer accepting events and there are still events in the
00451   // queue, then process remaining events.
00452   if (!mAcceptingEvents && PL_EventAvailable(mEventQueue))
00453       PL_ProcessPendingEvents(mEventQueue);
00454 
00455   CheckForDeactivation();
00456 
00457   if (mElderQueue) {
00458     nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
00459     if (elder)
00460       elder->ProcessPendingEvents();
00461   }
00462 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00463   --gEventQueueLogPPLevel;
00464 #endif
00465   return NS_OK;
00466 }
00467 
00468 NS_IMETHODIMP
00469 nsEventQueueImpl::EventLoop()
00470 {
00471   PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
00472 
00473   NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
00474 
00475   if (!correctThread)
00476     return NS_ERROR_FAILURE;
00477 
00478   PL_EventLoop(mEventQueue);
00479   return NS_OK;
00480 }
00481 
00482 NS_IMETHODIMP
00483 nsEventQueueImpl::EventAvailable(PRBool& aResult)
00484 {
00485   aResult = PL_EventAvailable(mEventQueue);
00486   return NS_OK;
00487 }
00488 
00489 NS_IMETHODIMP
00490 nsEventQueueImpl::GetEvent(PLEvent** aResult)
00491 {
00492   *aResult = PL_GetEvent(mEventQueue);
00493   CheckForDeactivation();
00494   return NS_OK;
00495 }
00496 
00497 NS_IMETHODIMP
00498 nsEventQueueImpl::HandleEvent(PLEvent* aEvent)
00499 {
00500   PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
00501   NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
00502   if (!correctThread)
00503     return NS_ERROR_FAILURE;
00504 
00505   nsresult rv;
00506   ListenerCaller caller(this, &rv);
00507   NS_ENSURE_SUCCESS(rv, rv);
00508   
00509 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00510   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00511          ("EventQueue: handle event [queue=%lx, accept=%d, could=%d]",
00512          (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
00513   ++gEventQueueLogCount;
00514 #endif
00515   PL_HandleEvent(aEvent);
00516   return NS_OK;
00517 }
00518 
00519 NS_IMETHODIMP
00520 nsEventQueueImpl::WaitForEvent(PLEvent** aResult)
00521 {
00522   PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
00523   NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
00524   if (!correctThread)
00525     return NS_ERROR_FAILURE;
00526 
00527 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00528 PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00529        ("EventQueue: wait for event [queue=%lx, accept=%d, could=%d]",
00530        (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
00531 ++gEventQueueLogCount;
00532 #endif
00533   *aResult = PL_WaitForEvent(mEventQueue);
00534   CheckForDeactivation();
00535   return NS_OK;
00536 }
00537 
00538 NS_IMETHODIMP_(PRInt32)
00539 nsEventQueueImpl::GetEventQueueSelectFD()
00540 {
00541   return PL_GetEventQueueSelectFD(mEventQueue);
00542 }
00543 
00544 NS_METHOD
00545 nsEventQueueImpl::Create(nsISupports *aOuter,
00546                          REFNSIID aIID,
00547                          void **aResult)
00548 {
00549   nsEventQueueImpl* evt = new nsEventQueueImpl();
00550   if (evt == NULL)
00551     return NS_ERROR_OUT_OF_MEMORY;
00552   nsresult rv = evt->QueryInterface(aIID, aResult);
00553   if (NS_FAILED(rv)) {
00554     delete evt;
00555   }
00556   return rv;
00557 }
00558 
00559 // ---------------- nsPIEventQueueChain -----------------
00560 
00561 NS_IMETHODIMP
00562 nsEventQueueImpl::AppendQueue(nsIEventQueue *aQueue)
00563 {
00564   nsresult      rv;
00565   nsCOMPtr<nsIEventQueue> end;
00566   nsCOMPtr<nsPIEventQueueChain> queueChain(do_QueryInterface(aQueue));
00567 
00568   if (!aQueue)
00569     return NS_ERROR_NO_INTERFACE;
00570 
00571 /* this would be nice
00572   NS_ASSERTION(aQueue->mYoungerQueue == NULL && aQueue->mElderQueue == NULL,
00573                "event queue repeatedly appended to queue chain");
00574 */
00575   rv = NS_ERROR_NO_INTERFACE;
00576 
00577 #ifdef NS_DEBUG
00578   int depth = 0;
00579   nsEventQueueImpl *next = this;
00580   while (next && depth < 100) {
00581     next = NS_STATIC_CAST(nsEventQueueImpl *, next->mYoungerQueue);
00582     ++depth;
00583   }
00584   if (depth > 5) {
00585     char warning[80];
00586     PR_snprintf(warning, sizeof(warning),
00587       "event queue chain length is %d. this is almost certainly a leak.", depth);
00588     NS_WARNING(warning);
00589   }
00590 #endif
00591 
00592   // (be careful doing this outside nsEventQueueService's mEventQMonitor)
00593 
00594   GetYoungest(getter_AddRefs(end));
00595   nsCOMPtr<nsPIEventQueueChain> endChain(do_QueryInterface(end));
00596   if (endChain) {
00597     endChain->SetYounger(queueChain);
00598     queueChain->SetElder(endChain);
00599     rv = NS_OK;
00600   }
00601   return rv;
00602 }
00603 
00604 NS_IMETHODIMP
00605 nsEventQueueImpl::Unlink()
00606 {
00607   nsCOMPtr<nsPIEventQueueChain> young = mYoungerQueue,
00608                                 old = mElderQueue;
00609 
00610 #if defined(PR_LOGGING) && defined(DEBUG_danm)
00611   PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
00612          ("EventQueue: unlink [queue=%lx, younger=%lx, elder=%lx]",
00613          (long)mEventQueue,(long)mYoungerQueue, (long)mElderQueue.get()));
00614   ++gEventQueueLogCount;
00615 #endif
00616 
00617   // this is probably OK, but shouldn't happen by design, so tell me if it does
00618   NS_ASSERTION(!mYoungerQueue, "event queue chain broken in middle");
00619 
00620   // break links early in case the Release cascades back onto us
00621   mYoungerQueue = nsnull;
00622   mElderQueue = nsnull;
00623 
00624   if (young)
00625     young->SetElder(old);
00626   if (old) {
00627     old->SetYounger(young);
00628   }
00629   return NS_OK;
00630 }
00631 
00632 NS_IMETHODIMP
00633 nsEventQueueImpl::GetYoungest(nsIEventQueue **aQueue)
00634 {
00635   if (mYoungerQueue)
00636     return mYoungerQueue->GetYoungest(aQueue);
00637 
00638   nsIEventQueue *answer = NS_STATIC_CAST(nsIEventQueue *, this);
00639   NS_ADDREF(answer);
00640   *aQueue = answer;
00641   return NS_OK;
00642 }
00643 
00644 NS_IMETHODIMP
00645 nsEventQueueImpl::GetYoungestActive(nsIEventQueue **aQueue)
00646 {
00647   nsCOMPtr<nsIEventQueue> answer;
00648 
00649   if (mYoungerQueue)
00650     mYoungerQueue->GetYoungestActive(getter_AddRefs(answer));
00651   if (!answer) {
00652     if (mAcceptingEvents && mCouldHaveEvents)
00653       answer = NS_STATIC_CAST(nsIEventQueue *, this);
00654   }
00655   *aQueue = answer;
00656   NS_IF_ADDREF(*aQueue);
00657   return NS_OK;
00658 }
00659 
00660 NS_IMETHODIMP
00661 nsEventQueueImpl::SetYounger(nsPIEventQueueChain *aQueue)
00662 {
00663   mYoungerQueue = aQueue;
00664   return NS_OK;
00665 }
00666 
00667 NS_IMETHODIMP
00668 nsEventQueueImpl::SetElder(nsPIEventQueueChain *aQueue)
00669 {
00670   mElderQueue = aQueue;
00671   return NS_OK;
00672 }
00673 
00674 NS_IMETHODIMP
00675 nsEventQueueImpl::GetYounger(nsIEventQueue **aQueue)
00676 {
00677   if (!mYoungerQueue) {
00678     *aQueue = nsnull;
00679     return NS_OK;
00680   }
00681   return mYoungerQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue);
00682 }
00683 
00684 NS_IMETHODIMP
00685 nsEventQueueImpl::GetElder(nsIEventQueue **aQueue)
00686 {
00687   if (!mElderQueue) {
00688     *aQueue = nsnull;
00689     return NS_OK;
00690   }
00691   return mElderQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue);
00692 }
00693 
00694 NS_IMETHODIMP
00695 nsEventQueueImpl::RevokeEventsInternal(void* aOwner)
00696 {
00697   PL_RevokeEvents(mEventQueue, aOwner);
00698   if (mElderQueue) {
00699     mElderQueue->RevokeEventsInternal(aOwner);
00700   }
00701   return NS_OK;
00702 }