From 24983c6525fd05be2f0baca6079fd66dcf648806 Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Tue, 4 May 1999 23:35:47 +0000 Subject: [PATCH] Committing the changes to support the new nsIEventQueue interface and nested queues in the event queue service. --- xpcom/src/Makefile.in | 62 -------- xpcom/src/makefile.win | 112 -------------- xpcom/src/nsEventQueue.cpp | 106 +++++++++++++ xpcom/src/nsEventQueue.h | 60 ++++++++ xpcom/src/nsEventQueueService.cpp | 208 ++++++++++++++++++++++++-- xpcom/src/nsXPComFactory.cpp | 71 --------- xpcom/threads/nsEventQueue.cpp | 106 +++++++++++++ xpcom/threads/nsEventQueue.h | 60 ++++++++ xpcom/threads/nsEventQueueService.cpp | 208 ++++++++++++++++++++++++-- 9 files changed, 718 insertions(+), 275 deletions(-) create mode 100644 xpcom/src/nsEventQueue.cpp create mode 100644 xpcom/src/nsEventQueue.h create mode 100644 xpcom/threads/nsEventQueue.cpp create mode 100644 xpcom/threads/nsEventQueue.h diff --git a/xpcom/src/Makefile.in b/xpcom/src/Makefile.in index 520c3d3d599..e69de29bb2d 100644 --- a/xpcom/src/Makefile.in +++ b/xpcom/src/Makefile.in @@ -1,62 +0,0 @@ -#!gmake -# The contents of this file are subject to the Netscape Public License -# Version 1.0 (the "NPL"); you may not use this file except in -# compliance with the NPL. You may obtain a copy of the NPL at -# http://www.mozilla.org/NPL/ -# -# Software distributed under the NPL is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL -# for the specific language governing rights and limitations under the -# NPL. -# -# The Initial Developer of this code under the NPL is Netscape -# Communications Corporation. Portions created by Netscape are -# Copyright (C) 1998 Netscape Communications Corporation. All Rights -# Reserved. - -DEPTH = ../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -MODULE = xpcom -LIBRARY_NAME = xpcom - -CSRCS = plvector.c \ - $(NULL) - -CPPSRCS = \ - nsCOMPtr.cpp \ - nsDebug.cpp \ - nsHashtable.cpp \ - nsID.cpp \ - nsComponentManager.cpp \ - nsEnumeratorUtils.cpp \ - nsEmptyEnumerator.cpp \ - nsRepository.cpp \ - nsServiceManager.cpp \ - nsSupportsArray.cpp \ - nsSupportsArrayEnumerator.cpp \ - nsConjoiningEnumerator.cpp \ - nsTraceRefcnt.cpp \ - nsXPComFactory.cpp \ - nsXPIDLString.cpp \ - nsEventQueueService.cpp \ - xcDll.cpp \ - nsAllocator.cpp \ - nsGenericFactory.cpp \ - nsRegistry.cpp \ - $(NULL) - -# XXX temporary, until I fix the RDF cursor/enumerator conspiracy -EXPORTS = nsSupportsArrayEnumerator.h - -EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) - -DEFINES += -D_IMPL_NS_COM -DUSE_NSREG - -REQUIRES = $(MODULE) libreg - -include $(topsrcdir)/config/rules.mk diff --git a/xpcom/src/makefile.win b/xpcom/src/makefile.win index ecdb90736f9..e69de29bb2d 100644 --- a/xpcom/src/makefile.win +++ b/xpcom/src/makefile.win @@ -1,112 +0,0 @@ -#!nmake -# -# The contents of this file are subject to the Netscape Public License -# Version 1.0 (the "NPL"); you may not use this file except in -# compliance with the NPL. You may obtain a copy of the NPL at -# http://www.mozilla.org/NPL/ -# -# Software distributed under the NPL is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL -# for the specific language governing rights and limitations under the -# NPL. -# -# The Initial Developer of this code under the NPL is Netscape -# Communications Corporation. Portions created by Netscape are -# Copyright (C) 1998 Netscape Communications Corporation. All Rights -# Reserved. - -IGNORE_MANIFEST=1 - -MAKE_OBJ_TYPE = DLL - -DEPTH=..\.. - -LINCS = \ - -I$(PUBLIC)\xpcom \ - -I$(PUBLIC)\libreg \ - $(NULL) - -LLIBS = \ - $(LIBNSPR) \ - $(DIST)\lib\plc3.lib \ - $(DIST)\lib\libreg32.lib \ -!if "$(MOZ_BITS)"=="32" && defined(MOZ_DEBUG) && defined(GLOWCODE) - $(GLOWDIR)\glowcode.lib \ -!endif -!if defined(MOZ_TRACE_XPCOM_REFCNT) - imagehlp.lib \ -!endif - $(NULL) - -LIBNAME = .\$(OBJDIR)\xpcom$(MOZ_BITS) -DLL = $(LIBNAME).dll - -LCFLAGS = -D_IMPL_NS_COM -DUSE_NSREG -DWIN32_LEAN_AND_MEAN - -CSRCS = \ - plvector.c \ - $(NULL) - -C_OBJS = \ - .\$(OBJDIR)\plvector.obj \ - $(NULL) - -CPPSRCS = \ - nsDebug.cpp \ - nsEnumeratorUtils.cpp \ - nsHashtable.cpp \ - nsID.cpp \ - nsCOMPtr.cpp \ - nsComponentManager.cpp \ - nsEnumeratorUtils.cpp \ - nsEmptyEnumerator.cpp \ - nsRepository.cpp \ - nsServiceManager.cpp \ - nsSupportsArray.cpp \ - nsSupportsArrayEnumerator.cpp \ - nsConjoiningEnumerator.cpp \ - nsTraceRefcnt.cpp \ - nsRegistry.cpp \ - nsXPComFactory.cpp \ - nsXPIDLString.cpp \ - nsEventQueueService.cpp \ - nsAllocator.cpp \ - xcDll.cpp \ - nsGenericFactory.cpp \ - $(NULL) - -CPP_OBJS = \ - .\$(OBJDIR)\nsDebug.obj \ - .\$(OBJDIR)\nsHashtable.obj \ - .\$(OBJDIR)\nsID.obj \ - .\$(OBJDIR)\nsCOMPtr.obj \ - .\$(OBJDIR)\nsEnumeratorUtils.obj \ - .\$(OBJDIR)\nsEmptyEnumerator.obj \ - .\$(OBJDIR)\nsComponentManager.obj \ - .\$(OBJDIR)\nsRepository.obj \ - .\$(OBJDIR)\nsServiceManager.obj \ - .\$(OBJDIR)\nsSupportsArray.obj \ - .\$(OBJDIR)\nsSupportsArrayEnumerator.obj \ - .\$(OBJDIR)\nsConjoiningEnumerator.obj \ - .\$(OBJDIR)\nsTraceRefcnt.obj \ - .\$(OBJDIR)\nsRegistry.obj \ - .\$(OBJDIR)\nsXPComFactory.obj \ - .\$(OBJDIR)\nsXPIDLString.obj \ - .\$(OBJDIR)\nsEventQueueService.obj \ - .\$(OBJDIR)\nsAllocator.obj \ - .\$(OBJDIR)\xcDll.obj \ - .\$(OBJDIR)\nsGenericFactory.obj \ - $(NULL) - -MODULE = xpcom - -# XXX temporary, until I fix the RDF cursor/enumerator conspiracy -EXPORTS = nsSupportsArrayEnumerator.h - -include <$(DEPTH)\config\rules.mak> - -libs:: $(DLL) - $(MAKE_INSTALL) $(LIBNAME).$(DLL_SUFFIX) $(DIST)\bin - $(MAKE_INSTALL) $(LIBNAME).$(LIB_SUFFIX) $(DIST)\lib - - diff --git a/xpcom/src/nsEventQueue.cpp b/xpcom/src/nsEventQueue.cpp new file mode 100644 index 00000000000..99c3aeb7324 --- /dev/null +++ b/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/xpcom/src/nsEventQueue.h b/xpcom/src/nsEventQueue.h new file mode 100644 index 00000000000..8c323013302 --- /dev/null +++ b/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/xpcom/src/nsEventQueueService.cpp b/xpcom/src/nsEventQueueService.cpp index c4c2cdc82c3..63c40524f28 100644 --- a/xpcom/src/nsEventQueueService.cpp +++ b/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/xpcom/src/nsXPComFactory.cpp b/xpcom/src/nsXPComFactory.cpp index 3435476fca1..e69de29bb2d 100644 --- a/xpcom/src/nsXPComFactory.cpp +++ b/xpcom/src/nsXPComFactory.cpp @@ -1,71 +0,0 @@ -/* -*- 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 "nsXPComFactory.h" -#include "nsXPComCIID.h" -#include "nsAllocator.h" -#include "nsGenericFactory.h" - -static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); - -nsresult NS_NewEventQueueServiceFactory(nsIFactory** aResult); - -/* - * Define the global NSGetFactory(...) entry point for the xpcom DLL... - */ -#if defined(XP_MAC) && defined(MAC_STATIC) -extern "C" NS_EXPORT nsresult -NSGetFactory_XPCOM_DLL(nsISupports* serviceMgr, - const nsCID &aClass, - const char *aClassName, - const char *aProgID, - nsIFactory **aFactory) -#else -extern "C" NS_EXPORT nsresult -NSGetFactory(nsISupports* serviceMgr, - const nsCID &aClass, - const char *aClassName, - const char *aProgID, - nsIFactory **aFactory) -#endif -{ - if (NULL == aFactory) { - return NS_ERROR_NULL_POINTER; - } - - nsresult rv = NS_OK; - if (aClass.Equals(kEventQueueServiceCID)) { - rv = NS_NewEventQueueServiceFactory(aFactory); - } else { - // Use generic factories for the rest. - nsGenericFactory* factory = NULL; - if (aClass.Equals(nsAllocatorImpl::CID())) { - factory = new nsGenericFactory(&nsAllocatorImpl::Create); - } else if (aClass.Equals(nsGenericFactory::CID())) { - // whoa, create a generic factory that creates generic factories! - factory = new nsGenericFactory(&nsGenericFactory::Create); - } - if (factory != NULL) { - factory->AddRef(); - *aFactory = factory; - } else { - rv = NS_ERROR_OUT_OF_MEMORY; - } - } - return rv; -} diff --git a/xpcom/threads/nsEventQueue.cpp b/xpcom/threads/nsEventQueue.cpp new file mode 100644 index 00000000000..99c3aeb7324 --- /dev/null +++ b/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/xpcom/threads/nsEventQueue.h b/xpcom/threads/nsEventQueue.h new file mode 100644 index 00000000000..8c323013302 --- /dev/null +++ b/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/xpcom/threads/nsEventQueueService.cpp b/xpcom/threads/nsEventQueueService.cpp index c4c2cdc82c3..63c40524f28 100644 --- a/xpcom/threads/nsEventQueueService.cpp +++ b/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; }