diff --git a/mozilla/xpcom/src/Makefile.in b/mozilla/xpcom/src/Makefile.in index 520c3d3d599..2014c56b8ad 100644 --- a/mozilla/xpcom/src/Makefile.in +++ b/mozilla/xpcom/src/Makefile.in @@ -44,6 +44,7 @@ CPPSRCS = \ nsXPComFactory.cpp \ nsXPIDLString.cpp \ nsEventQueueService.cpp \ + nsEventQueue.cpp \ xcDll.cpp \ nsAllocator.cpp \ nsGenericFactory.cpp \ diff --git a/mozilla/xpcom/src/makefile.win b/mozilla/xpcom/src/makefile.win index ecdb90736f9..5bf6c0dad5c 100644 --- a/mozilla/xpcom/src/makefile.win +++ b/mozilla/xpcom/src/makefile.win @@ -70,6 +70,7 @@ CPPSRCS = \ nsXPComFactory.cpp \ nsXPIDLString.cpp \ nsEventQueueService.cpp \ + nsEventQueue.cpp \ nsAllocator.cpp \ xcDll.cpp \ nsGenericFactory.cpp \ @@ -93,6 +94,7 @@ CPP_OBJS = \ .\$(OBJDIR)\nsXPComFactory.obj \ .\$(OBJDIR)\nsXPIDLString.obj \ .\$(OBJDIR)\nsEventQueueService.obj \ + .\$(OBJDIR)\nsEventQueue.obj \ .\$(OBJDIR)\nsAllocator.obj \ .\$(OBJDIR)\xcDll.obj \ .\$(OBJDIR)\nsGenericFactory.obj \ diff --git a/mozilla/xpcom/src/nsEventQueue.cpp b/mozilla/xpcom/src/nsEventQueue.cpp new file mode 100644 index 00000000000..99c3aeb7324 --- /dev/null +++ b/mozilla/xpcom/src/nsEventQueue.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ + +#include "nsEventQueue.h" + +nsEventQueueImpl::nsEventQueueImpl() +{ + NS_INIT_REFCNT(); + + mEventQueue = NULL; + +} + +nsEventQueueImpl::~nsEventQueueImpl() +{ + if (NULL != mEventQueue) { + PL_DestroyEventQueue(mEventQueue); + } +} + +NS_IMETHODIMP +nsEventQueueImpl::Init() +{ + mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", PR_GetCurrentThread()); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue) +{ + mEventQueue = aQueue; + return NS_OK; +} + +/* nsISupports interface implementation... */ +NS_IMPL_ISUPPORTS(nsEventQueueImpl,kIEventQueueIID); + +/* nsIEventQueue interface implementation... */ + +NS_IMETHODIMP_(PRStatus) +nsEventQueueImpl::PostEvent(PLEvent* aEvent) +{ + return PL_PostEvent(mEventQueue, aEvent); +} + +NS_IMETHODIMP +nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent) +{ + PL_PostSynchronousEvent(mEventQueue, aEvent); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::ProcessPendingEvents() +{ + PL_ProcessPendingEvents(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EventAvailable(PRBool& aResult) +{ + aResult = PL_EventAvailable(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetEvent(PLEvent** aResult) +{ + *aResult = PL_GetEvent(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP_(PRInt32) +nsEventQueueImpl::GetEventQueueSelectFD() +{ + return PL_GetEventQueueSelectFD(mEventQueue); +} + +NS_METHOD +nsEventQueueImpl::Create(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + nsEventQueueImpl* evt = new nsEventQueueImpl(); + if (evt == NULL) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = evt->QueryInterface(aIID, aResult); + return rv; +} diff --git a/mozilla/xpcom/src/nsEventQueue.h b/mozilla/xpcom/src/nsEventQueue.h new file mode 100644 index 00000000000..8c323013302 --- /dev/null +++ b/mozilla/xpcom/src/nsEventQueue.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ + +#include "prmon.h" +#include "nsIEventQueue.h" +#include "nsXPComFactory.h" + +static NS_DEFINE_IID(kIEventQueueIID, NS_IEVENTQUEUE_IID); + +class nsEventQueueImpl : public nsIEventQueue +{ +public: + nsEventQueueImpl(); + + // nsISupports interface... + NS_DECL_ISUPPORTS + + // nsIEventQueue interface... + NS_IMETHOD_(PRStatus) PostEvent(PLEvent* aEvent); + NS_IMETHOD PostSynchronousEvent(PLEvent* aEvent); + NS_IMETHOD ProcessPendingEvents(); + NS_IMETHOD EventAvailable(PRBool& aResult); + NS_IMETHOD GetEvent(PLEvent** aResult); + + NS_IMETHOD_(PRInt32) GetEventQueueSelectFD(); + + NS_IMETHOD Init(); + NS_IMETHOD InitFromPLQueue(PLEventQueue* aQueue); + + // Helpers + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + static const nsCID& CID() { static nsCID cid = NS_EVENTQUEUE_CID; return cid; } + +protected: + ~nsEventQueueImpl(); + +private: + PLEventQueue* mEventQueue; +}; + + + diff --git a/mozilla/xpcom/src/nsEventQueueService.cpp b/mozilla/xpcom/src/nsEventQueueService.cpp index c4c2cdc82c3..63c40524f28 100644 --- a/mozilla/xpcom/src/nsEventQueueService.cpp +++ b/mozilla/xpcom/src/nsEventQueueService.cpp @@ -17,15 +17,14 @@ * Netscape Communications Corporation. All Rights Reserved. */ #include "prmon.h" +#include "nsComponentManager.h" #include "nsIEventQueueService.h" +#include "nsIEventQueue.h" #include "nsHashtable.h" #include "nsXPComFactory.h" - static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); - - // XXX move to nsID.h or nsHashtable.h? (copied from nsComponentManager.cpp) class ThreadKey: public nsHashKey { private: @@ -50,6 +49,66 @@ public: }; +/* This class is used with the EventQueueEntries to allow us to nest + event queues */ +class EventQueueStack +{ +public: + EventQueueStack(EventQueueStack* next = NULL); + ~EventQueueStack(); + + nsIEventQueue* GetEventQueue(); + EventQueueStack* GetNext(); + void SetNext(EventQueueStack* aStack); + +private: + nsIEventQueue* mEventQueue; + EventQueueStack* mNextQueue; +}; + +static NS_DEFINE_IID(kIEventQueueIID, NS_IEVENTQUEUE_IID); +static NS_DEFINE_IID(kEventQueueCID, NS_EVENTQUEUE_CID); + +EventQueueStack::EventQueueStack(EventQueueStack* next) +:mNextQueue(next) +{ + // Create our thread queue using the component manager + if (NS_FAILED(nsComponentManager::CreateInstance(kEventQueueCID, NULL, kIEventQueueIID, + (void**)&mEventQueue))) { + mEventQueue = NULL; + } + + if (NS_FAILED(mEventQueue->Init())) + mEventQueue = NULL; +} + +EventQueueStack::~EventQueueStack() +{ + // Destroy our thread queue. + NS_IF_RELEASE(mEventQueue); + + if (mNextQueue) + { + delete mNextQueue; + } +} + +nsIEventQueue* EventQueueStack::GetEventQueue() +{ + NS_ADDREF(mEventQueue); + return mEventQueue; +} + +EventQueueStack* EventQueueStack::GetNext() +{ + return mNextQueue; +} + +void EventQueueStack::SetNext(EventQueueStack* aStack) +{ + mNextQueue = aStack; +} + /* * This class maintains the data associated with each entry in the EventQueue * service's hash table... @@ -66,10 +125,13 @@ public: // nsISupports interface... NS_DECL_ISUPPORTS - PLEventQueue* GetEventQueue(void); + nsIEventQueue* GetEventQueue(void); + + void PushQueue(void); + void PopQueue(void); private: - PLEventQueue* mEventQueue; + EventQueueStack* mQueueStack; }; /* nsISupports interface implementation... */ @@ -79,22 +141,42 @@ EventQueueEntry::EventQueueEntry() { NS_INIT_REFCNT(); - mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", PR_GetCurrentThread()); + mQueueStack = new EventQueueStack(); } EventQueueEntry::~EventQueueEntry() { - if (NULL != mEventQueue) { - PL_DestroyEventQueue(mEventQueue); - } + // Delete our stack + delete mQueueStack; } -PLEventQueue* EventQueueEntry::GetEventQueue(void) +nsIEventQueue* EventQueueEntry::GetEventQueue(void) { - return mEventQueue; + // Return the current event queue on our stack. + nsIEventQueue* answer = NULL; + if (mQueueStack) + answer = mQueueStack->GetEventQueue(); // This call addrefs the queue + return answer; } +void EventQueueEntry::PushQueue(void) +{ + // Make a new thread queue, connect it to our current stack, and then + // set it to be the top of our stack. + mQueueStack = new EventQueueStack(mQueueStack); +} +void EventQueueEntry::PopQueue(void) +{ + EventQueueStack* popped = mQueueStack; + if (mQueueStack) { + mQueueStack = mQueueStack->GetNext(); + popped->SetNext(NULL); + } + + // This will result in the queue being released. + delete popped; +} class nsEventQueueServiceImpl : public nsIEventQueueService { @@ -107,7 +189,12 @@ public: // nsIEventQueueService interface... NS_IMETHOD CreateThreadEventQueue(void); NS_IMETHOD DestroyThreadEventQueue(void); - NS_IMETHOD GetThreadEventQueue(PRThread* aThread, PLEventQueue** aResult); + NS_IMETHOD GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult); + + NS_IMETHOD CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult); + + NS_IMETHOD PushThreadEventQueue(void); + NS_IMETHOD PopThreadEventQueue(void); #ifdef XP_MAC NS_IMETHOD ProcessEvents(); @@ -211,9 +298,94 @@ nsEventQueueServiceImpl::DestroyThreadEventQueue(void) return rv; } +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult) +{ + // Create our thread queue using the component manager + nsresult rv; + nsIEventQueue* aQueue; + if (NS_FAILED(rv = nsComponentManager::CreateInstance(kEventQueueCID, NULL, kIEventQueueIID, + (void**)&aQueue))) { + return rv; + } + + if (NS_FAILED(rv = aQueue->InitFromPLQueue(aPLEventQueue))) { + NS_IF_RELEASE(aQueue); + return rv; + } + + *aResult = aQueue; + return NS_OK; +} NS_IMETHODIMP -nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, PLEventQueue** aResult) +nsEventQueueServiceImpl::PushThreadEventQueue() +{ + nsresult rv = NS_OK; + ThreadKey key(PR_GetCurrentThread()); + EventQueueEntry* evQueueEntry; + + /* Enter the lock which protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + /* Only create one event queue per thread... */ + evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key); + if (NULL == evQueueEntry) { + evQueueEntry = new EventQueueEntry(); + if (NULL == evQueueEntry) { + rv = NS_ERROR_OUT_OF_MEMORY; + goto done; + } + mEventQTable->Put(&key, evQueueEntry); + } + else { + // An entry was already present. We need to push a new + // queue onto our stack. + evQueueEntry->PushQueue(); + } + + NS_ADDREF(evQueueEntry); + +done: + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::PopThreadEventQueue(void) +{ + nsresult rv = NS_OK; + ThreadKey key(PR_GetCurrentThread()); + EventQueueEntry* evQueueEntry; + + /* Enter the lock which protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key); + if (NULL != evQueueEntry) { + nsrefcnt refcnt; + + NS_RELEASE2(evQueueEntry, refcnt); + // Remove the entry from the hash table if this was the last reference... + if (0 == refcnt) { + mEventQTable->Remove(&key); + } + else { + // We must be popping. + evQueueEntry->PopQueue(); + } + } else { + rv = NS_ERROR_FAILURE; + } + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult) { nsresult rv = NS_OK; EventQueueEntry* evQueueEntry; @@ -230,7 +402,7 @@ nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, PLEventQueue** a evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key); if (NULL != evQueueEntry) { - *aResult = evQueueEntry->GetEventQueue(); + *aResult = evQueueEntry->GetEventQueue(); // Queue addrefing is done by this call. } else { // XXX: Need error code for requesting an event queue when none exists... *aResult = NULL; @@ -248,7 +420,13 @@ done: static PRBool EventDispatchingFunc(nsHashKey *aKey, void *aData, void* closure) { EventQueueEntry* entry = (EventQueueEntry*) aData; - PL_ProcessPendingEvents( entry->GetEventQueue() ); + nsIEventQueue* eventQueue = entry->GetEventQueue(); + + if (eventQueue) { + eventQueue->ProcessPendingEvents(); + NS_RELEASE(eventQueue); + } + return true; } diff --git a/mozilla/xpcom/src/nsXPComFactory.cpp b/mozilla/xpcom/src/nsXPComFactory.cpp index 3435476fca1..843dfadefe9 100644 --- a/mozilla/xpcom/src/nsXPComFactory.cpp +++ b/mozilla/xpcom/src/nsXPComFactory.cpp @@ -19,6 +19,7 @@ #include "nsXPComFactory.h" #include "nsXPComCIID.h" #include "nsAllocator.h" +#include "nsEventQueue.h" #include "nsGenericFactory.h" static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); @@ -56,6 +57,8 @@ NSGetFactory(nsISupports* serviceMgr, nsGenericFactory* factory = NULL; if (aClass.Equals(nsAllocatorImpl::CID())) { factory = new nsGenericFactory(&nsAllocatorImpl::Create); + } else if (aClass.Equals(nsEventQueueImpl::CID())) { + factory = new nsGenericFactory(&nsEventQueueImpl::Create); } else if (aClass.Equals(nsGenericFactory::CID())) { // whoa, create a generic factory that creates generic factories! factory = new nsGenericFactory(&nsGenericFactory::Create); diff --git a/mozilla/xpcom/threads/nsEventQueue.cpp b/mozilla/xpcom/threads/nsEventQueue.cpp new file mode 100644 index 00000000000..99c3aeb7324 --- /dev/null +++ b/mozilla/xpcom/threads/nsEventQueue.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ + +#include "nsEventQueue.h" + +nsEventQueueImpl::nsEventQueueImpl() +{ + NS_INIT_REFCNT(); + + mEventQueue = NULL; + +} + +nsEventQueueImpl::~nsEventQueueImpl() +{ + if (NULL != mEventQueue) { + PL_DestroyEventQueue(mEventQueue); + } +} + +NS_IMETHODIMP +nsEventQueueImpl::Init() +{ + mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", PR_GetCurrentThread()); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue) +{ + mEventQueue = aQueue; + return NS_OK; +} + +/* nsISupports interface implementation... */ +NS_IMPL_ISUPPORTS(nsEventQueueImpl,kIEventQueueIID); + +/* nsIEventQueue interface implementation... */ + +NS_IMETHODIMP_(PRStatus) +nsEventQueueImpl::PostEvent(PLEvent* aEvent) +{ + return PL_PostEvent(mEventQueue, aEvent); +} + +NS_IMETHODIMP +nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent) +{ + PL_PostSynchronousEvent(mEventQueue, aEvent); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::ProcessPendingEvents() +{ + PL_ProcessPendingEvents(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EventAvailable(PRBool& aResult) +{ + aResult = PL_EventAvailable(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetEvent(PLEvent** aResult) +{ + *aResult = PL_GetEvent(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP_(PRInt32) +nsEventQueueImpl::GetEventQueueSelectFD() +{ + return PL_GetEventQueueSelectFD(mEventQueue); +} + +NS_METHOD +nsEventQueueImpl::Create(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + nsEventQueueImpl* evt = new nsEventQueueImpl(); + if (evt == NULL) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = evt->QueryInterface(aIID, aResult); + return rv; +} diff --git a/mozilla/xpcom/threads/nsEventQueue.h b/mozilla/xpcom/threads/nsEventQueue.h new file mode 100644 index 00000000000..8c323013302 --- /dev/null +++ b/mozilla/xpcom/threads/nsEventQueue.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ + +#include "prmon.h" +#include "nsIEventQueue.h" +#include "nsXPComFactory.h" + +static NS_DEFINE_IID(kIEventQueueIID, NS_IEVENTQUEUE_IID); + +class nsEventQueueImpl : public nsIEventQueue +{ +public: + nsEventQueueImpl(); + + // nsISupports interface... + NS_DECL_ISUPPORTS + + // nsIEventQueue interface... + NS_IMETHOD_(PRStatus) PostEvent(PLEvent* aEvent); + NS_IMETHOD PostSynchronousEvent(PLEvent* aEvent); + NS_IMETHOD ProcessPendingEvents(); + NS_IMETHOD EventAvailable(PRBool& aResult); + NS_IMETHOD GetEvent(PLEvent** aResult); + + NS_IMETHOD_(PRInt32) GetEventQueueSelectFD(); + + NS_IMETHOD Init(); + NS_IMETHOD InitFromPLQueue(PLEventQueue* aQueue); + + // Helpers + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + static const nsCID& CID() { static nsCID cid = NS_EVENTQUEUE_CID; return cid; } + +protected: + ~nsEventQueueImpl(); + +private: + PLEventQueue* mEventQueue; +}; + + + diff --git a/mozilla/xpcom/threads/nsEventQueueService.cpp b/mozilla/xpcom/threads/nsEventQueueService.cpp index c4c2cdc82c3..63c40524f28 100644 --- a/mozilla/xpcom/threads/nsEventQueueService.cpp +++ b/mozilla/xpcom/threads/nsEventQueueService.cpp @@ -17,15 +17,14 @@ * Netscape Communications Corporation. All Rights Reserved. */ #include "prmon.h" +#include "nsComponentManager.h" #include "nsIEventQueueService.h" +#include "nsIEventQueue.h" #include "nsHashtable.h" #include "nsXPComFactory.h" - static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); - - // XXX move to nsID.h or nsHashtable.h? (copied from nsComponentManager.cpp) class ThreadKey: public nsHashKey { private: @@ -50,6 +49,66 @@ public: }; +/* This class is used with the EventQueueEntries to allow us to nest + event queues */ +class EventQueueStack +{ +public: + EventQueueStack(EventQueueStack* next = NULL); + ~EventQueueStack(); + + nsIEventQueue* GetEventQueue(); + EventQueueStack* GetNext(); + void SetNext(EventQueueStack* aStack); + +private: + nsIEventQueue* mEventQueue; + EventQueueStack* mNextQueue; +}; + +static NS_DEFINE_IID(kIEventQueueIID, NS_IEVENTQUEUE_IID); +static NS_DEFINE_IID(kEventQueueCID, NS_EVENTQUEUE_CID); + +EventQueueStack::EventQueueStack(EventQueueStack* next) +:mNextQueue(next) +{ + // Create our thread queue using the component manager + if (NS_FAILED(nsComponentManager::CreateInstance(kEventQueueCID, NULL, kIEventQueueIID, + (void**)&mEventQueue))) { + mEventQueue = NULL; + } + + if (NS_FAILED(mEventQueue->Init())) + mEventQueue = NULL; +} + +EventQueueStack::~EventQueueStack() +{ + // Destroy our thread queue. + NS_IF_RELEASE(mEventQueue); + + if (mNextQueue) + { + delete mNextQueue; + } +} + +nsIEventQueue* EventQueueStack::GetEventQueue() +{ + NS_ADDREF(mEventQueue); + return mEventQueue; +} + +EventQueueStack* EventQueueStack::GetNext() +{ + return mNextQueue; +} + +void EventQueueStack::SetNext(EventQueueStack* aStack) +{ + mNextQueue = aStack; +} + /* * This class maintains the data associated with each entry in the EventQueue * service's hash table... @@ -66,10 +125,13 @@ public: // nsISupports interface... NS_DECL_ISUPPORTS - PLEventQueue* GetEventQueue(void); + nsIEventQueue* GetEventQueue(void); + + void PushQueue(void); + void PopQueue(void); private: - PLEventQueue* mEventQueue; + EventQueueStack* mQueueStack; }; /* nsISupports interface implementation... */ @@ -79,22 +141,42 @@ EventQueueEntry::EventQueueEntry() { NS_INIT_REFCNT(); - mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", PR_GetCurrentThread()); + mQueueStack = new EventQueueStack(); } EventQueueEntry::~EventQueueEntry() { - if (NULL != mEventQueue) { - PL_DestroyEventQueue(mEventQueue); - } + // Delete our stack + delete mQueueStack; } -PLEventQueue* EventQueueEntry::GetEventQueue(void) +nsIEventQueue* EventQueueEntry::GetEventQueue(void) { - return mEventQueue; + // Return the current event queue on our stack. + nsIEventQueue* answer = NULL; + if (mQueueStack) + answer = mQueueStack->GetEventQueue(); // This call addrefs the queue + return answer; } +void EventQueueEntry::PushQueue(void) +{ + // Make a new thread queue, connect it to our current stack, and then + // set it to be the top of our stack. + mQueueStack = new EventQueueStack(mQueueStack); +} +void EventQueueEntry::PopQueue(void) +{ + EventQueueStack* popped = mQueueStack; + if (mQueueStack) { + mQueueStack = mQueueStack->GetNext(); + popped->SetNext(NULL); + } + + // This will result in the queue being released. + delete popped; +} class nsEventQueueServiceImpl : public nsIEventQueueService { @@ -107,7 +189,12 @@ public: // nsIEventQueueService interface... NS_IMETHOD CreateThreadEventQueue(void); NS_IMETHOD DestroyThreadEventQueue(void); - NS_IMETHOD GetThreadEventQueue(PRThread* aThread, PLEventQueue** aResult); + NS_IMETHOD GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult); + + NS_IMETHOD CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult); + + NS_IMETHOD PushThreadEventQueue(void); + NS_IMETHOD PopThreadEventQueue(void); #ifdef XP_MAC NS_IMETHOD ProcessEvents(); @@ -211,9 +298,94 @@ nsEventQueueServiceImpl::DestroyThreadEventQueue(void) return rv; } +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult) +{ + // Create our thread queue using the component manager + nsresult rv; + nsIEventQueue* aQueue; + if (NS_FAILED(rv = nsComponentManager::CreateInstance(kEventQueueCID, NULL, kIEventQueueIID, + (void**)&aQueue))) { + return rv; + } + + if (NS_FAILED(rv = aQueue->InitFromPLQueue(aPLEventQueue))) { + NS_IF_RELEASE(aQueue); + return rv; + } + + *aResult = aQueue; + return NS_OK; +} NS_IMETHODIMP -nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, PLEventQueue** aResult) +nsEventQueueServiceImpl::PushThreadEventQueue() +{ + nsresult rv = NS_OK; + ThreadKey key(PR_GetCurrentThread()); + EventQueueEntry* evQueueEntry; + + /* Enter the lock which protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + /* Only create one event queue per thread... */ + evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key); + if (NULL == evQueueEntry) { + evQueueEntry = new EventQueueEntry(); + if (NULL == evQueueEntry) { + rv = NS_ERROR_OUT_OF_MEMORY; + goto done; + } + mEventQTable->Put(&key, evQueueEntry); + } + else { + // An entry was already present. We need to push a new + // queue onto our stack. + evQueueEntry->PushQueue(); + } + + NS_ADDREF(evQueueEntry); + +done: + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::PopThreadEventQueue(void) +{ + nsresult rv = NS_OK; + ThreadKey key(PR_GetCurrentThread()); + EventQueueEntry* evQueueEntry; + + /* Enter the lock which protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key); + if (NULL != evQueueEntry) { + nsrefcnt refcnt; + + NS_RELEASE2(evQueueEntry, refcnt); + // Remove the entry from the hash table if this was the last reference... + if (0 == refcnt) { + mEventQTable->Remove(&key); + } + else { + // We must be popping. + evQueueEntry->PopQueue(); + } + } else { + rv = NS_ERROR_FAILURE; + } + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult) { nsresult rv = NS_OK; EventQueueEntry* evQueueEntry; @@ -230,7 +402,7 @@ nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, PLEventQueue** a evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key); if (NULL != evQueueEntry) { - *aResult = evQueueEntry->GetEventQueue(); + *aResult = evQueueEntry->GetEventQueue(); // Queue addrefing is done by this call. } else { // XXX: Need error code for requesting an event queue when none exists... *aResult = NULL; @@ -248,7 +420,13 @@ done: static PRBool EventDispatchingFunc(nsHashKey *aKey, void *aData, void* closure) { EventQueueEntry* entry = (EventQueueEntry*) aData; - PL_ProcessPendingEvents( entry->GetEventQueue() ); + nsIEventQueue* eventQueue = entry->GetEventQueue(); + + if (eventQueue) { + eventQueue->ProcessPendingEvents(); + NS_RELEASE(eventQueue); + } + return true; }