From eef8571946920b2fb80cc33f95148ee92d406dff Mon Sep 17 00:00:00 2001 From: "warren%netscape.com" Date: Wed, 27 Jan 1999 02:02:22 +0000 Subject: [PATCH] Added nsIAllocator and implementation. Made service manager services sticky'. git-svn-id: svn://10.0.0.236/trunk@18690 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/base/nsAllocator.cpp | 129 ++++++++++++++++++ mozilla/xpcom/base/nsAllocator.h | 93 +++++++++++++ mozilla/xpcom/base/nsIAllocator.h | 82 +++++++++++ mozilla/xpcom/components/nsRepository.cpp | 32 +---- mozilla/xpcom/components/nsServiceManager.cpp | 61 +++------ mozilla/xpcom/ds/nsHashtable.h | 26 ++++ mozilla/xpcom/public/makefile.win | 3 +- mozilla/xpcom/public/nsHashtable.h | 26 ++++ mozilla/xpcom/public/nsIAllocator.h | 82 +++++++++++ mozilla/xpcom/src/makefile.win | 2 + mozilla/xpcom/src/nsAllocator.cpp | 129 ++++++++++++++++++ mozilla/xpcom/src/nsAllocator.h | 93 +++++++++++++ mozilla/xpcom/src/nsRepository.cpp | 32 +---- mozilla/xpcom/src/nsServiceManager.cpp | 61 +++------ 14 files changed, 714 insertions(+), 137 deletions(-) create mode 100644 mozilla/xpcom/base/nsAllocator.cpp create mode 100644 mozilla/xpcom/base/nsAllocator.h create mode 100644 mozilla/xpcom/base/nsIAllocator.h create mode 100644 mozilla/xpcom/public/nsIAllocator.h create mode 100644 mozilla/xpcom/src/nsAllocator.cpp create mode 100644 mozilla/xpcom/src/nsAllocator.h diff --git a/mozilla/xpcom/base/nsAllocator.cpp b/mozilla/xpcom/base/nsAllocator.cpp new file mode 100644 index 00000000000..7b797761102 --- /dev/null +++ b/mozilla/xpcom/base/nsAllocator.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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. + */ + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of nsIAllocator using NSPR +//////////////////////////////////////////////////////////////////////////////// + +#include "nsAllocator.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIAllocatorIID, NS_IALLOCATOR_IID); + +nsAllocator::nsAllocator(nsISupports* outer) +{ + NS_INIT_AGGREGATED(outer); +} + +nsAllocator::~nsAllocator(void) +{ +} + +NS_IMPL_AGGREGATED(nsAllocator); + +NS_METHOD +nsAllocator::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIAllocatorIID) || + aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*) this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_METHOD +nsAllocator::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + if (outer && !aIID.Equals(kISupportsIID)) + return NS_NOINTERFACE; // XXX right error? + nsAllocator* mm = new nsAllocator(outer); + if (mm == NULL) + return NS_ERROR_OUT_OF_MEMORY; + mm->AddRef(); + if (aIID.Equals(kISupportsIID)) + *aInstancePtr = mm->GetInner(); + else + *aInstancePtr = mm; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_METHOD_(void*) +nsAllocator::Alloc(PRUint32 size) +{ + return PR_Malloc(size); +} + +NS_METHOD_(void*) +nsAllocator::Realloc(void* ptr, PRUint32 size) +{ + return PR_Realloc(ptr, size); +} + +NS_METHOD +nsAllocator::Free(void* ptr) +{ + PR_Free(ptr); + return NS_OK; +} + +NS_METHOD +nsAllocator::HeapMinimize(void) +{ +#ifdef XP_MAC + // This used to live in the memory allocators no Mac, but does no more + // Needs to be hooked up in the new world. +// CallCacheFlushers(0x7fffffff); +#endif + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsAllocatorFactory::nsAllocatorFactory(void) +{ +} + +nsAllocatorFactory::~nsAllocatorFactory(void) +{ +} + +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); +NS_IMPL_ISUPPORTS(nsAllocatorFactory, kIFactoryIID); + +NS_METHOD +nsAllocatorFactory::CreateInstance(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + return nsAllocator::Create(aOuter, aIID, aResult); +} + +NS_METHOD +nsAllocatorFactory::LockFactory(PRBool aLock) +{ + return NS_OK; // XXX what? +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/xpcom/base/nsAllocator.h b/mozilla/xpcom/base/nsAllocator.h new file mode 100644 index 00000000000..342f36ca3f4 --- /dev/null +++ b/mozilla/xpcom/base/nsAllocator.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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. + */ + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of nsIAllocator using NSPR +//////////////////////////////////////////////////////////////////////////////// + +#ifndef nsAllocator_h__ +#define nsAllocator_h__ + +#include "nsIAllocator.h" +#include "prmem.h" +#include "nsAgg.h" + +class nsAllocator : nsIAllocator { +public: + + /** + * Allocates a block of memory of a particular size. + * + * @param size - the size of the block to allocate + * @result the block of memory + */ + NS_IMETHOD_(void*) Alloc(PRUint32 size); + + /** + * Reallocates a block of memory to a new size. + * + * @param ptr - the block of memory to reallocate + * @param size - the new size + * @result the rellocated block of memory + */ + NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size); + + /** + * Frees a block of memory. + * + * @param ptr - the block of memory to free + */ + NS_IMETHOD Free(void* ptr); + + /** + * Attempts to shrink the heap. + */ + NS_IMETHOD HeapMinimize(void); + + //////////////////////////////////////////////////////////////////////////// + + nsAllocator(nsISupports* outer); + virtual ~nsAllocator(void); + + NS_DECL_AGGREGATED + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsIFactory.h" + +class nsAllocatorFactory : nsIFactory { +public: + NS_IMETHOD CreateInstance(nsISupports *aOuter, + REFNSIID aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + nsAllocatorFactory(void); + ~nsAllocatorFactory(void); + + NS_DECL_ISUPPORTS +}; + +//////////////////////////////////////////////////////////////////////////////// +#endif // nsAllocator_h__ diff --git a/mozilla/xpcom/base/nsIAllocator.h b/mozilla/xpcom/base/nsIAllocator.h new file mode 100644 index 00000000000..e6c25b8ad3e --- /dev/null +++ b/mozilla/xpcom/base/nsIAllocator.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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. + */ + +#ifndef nsIAllocator_h___ +#define nsIAllocator_h___ + +#include "nsISupports.h" + +/** + * Unlike IMalloc, this interface returns nsresults and doesn't + * implement the problematic GetSize and DidAlloc routines. + */ + +class nsIAllocator : public nsISupports { +public: + + /** + * Allocates a block of memory of a particular size. + * + * @param size - the size of the block to allocate + * @result the block of memory + */ + NS_IMETHOD_(void*) Alloc(PRUint32 size) = 0; + + /** + * Reallocates a block of memory to a new size. + * + * @param ptr - the block of memory to reallocate + * @param size - the new size + * @result the rellocated block of memory + */ + NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size) = 0; + + /** + * Frees a block of memory. + * + * @param ptr - the block of memory to free + */ + NS_IMETHOD Free(void* ptr) = 0; + + /** + * Attempts to shrink the heap. + */ + NS_IMETHOD HeapMinimize(void) = 0; + +}; + +#define NS_IALLOCATOR_IID \ +{ /* 56def700-b1b9-11d2-8177-006008119d7a */ \ + 0x56def700, \ + 0xb1b9, \ + 0x11d2, \ + {0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +// To get the global memory manager service: +#define NS_ALLOCATOR_CID \ +{ /* aafe6770-b1bb-11d2-8177-006008119d7a */ \ + 0xaafe6770, \ + 0xb1bb, \ + 0x11d2, \ + {0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +//////////////////////////////////////////////////////////////////////////////// + +#endif /* nsIAllocator_h___ */ diff --git a/mozilla/xpcom/components/nsRepository.cpp b/mozilla/xpcom/components/nsRepository.cpp index b696306f61c..a575abe5de9 100644 --- a/mozilla/xpcom/components/nsRepository.cpp +++ b/mozilla/xpcom/components/nsRepository.cpp @@ -86,28 +86,6 @@ public: } }; -class IDKey: public nsHashKey { -private: - nsID id; - -public: - IDKey(const nsID &aID) { - id = aID; - } - - PRUint32 HashValue(void) const { - return id.m0; - } - - PRBool Equals(const nsHashKey *aKey) const { - return (id.Equals(((const IDKey *) aKey)->id)); - } - - nsHashKey *Clone(void) const { - return new IDKey(id); - } -}; - #ifdef USE_NSREG #define USE_REGISTRY @@ -288,7 +266,7 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, PR_EnterMonitor(monitor); - IDKey key(aClass); + nsIDKey key(aClass); FactoryEntry *entry = (FactoryEntry*) factories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; @@ -452,7 +430,7 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, PR_EnterMonitor(monitor); - IDKey key(aClass); + nsIDKey key(aClass); factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL)); PR_ExitMonitor(monitor); @@ -499,7 +477,7 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, else #endif { - IDKey key(aClass); + nsIDKey key(aClass); factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary)); } @@ -530,7 +508,7 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, if (old == aFactory) { PR_EnterMonitor(monitor); - IDKey key(aClass); + nsIDKey key(aClass); FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key); delete entry; @@ -560,7 +538,7 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, delete [] buf; } - IDKey key(aClass); + nsIDKey key(aClass); FactoryEntry *old = (FactoryEntry *) factories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; diff --git a/mozilla/xpcom/components/nsServiceManager.cpp b/mozilla/xpcom/components/nsServiceManager.cpp index cc6b72efbf0..26d3fdaa264 100644 --- a/mozilla/xpcom/components/nsServiceManager.cpp +++ b/mozilla/xpcom/components/nsServiceManager.cpp @@ -21,29 +21,6 @@ #include "prcmon.h" #include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */ -// XXX move to nsID.h or nsHashtable.h? (copied from nsRepository.cpp) -class IDKey: public nsHashKey { -private: - nsID id; - -public: - IDKey(const nsID &aID) { - id = aID; - } - - PRUint32 HashValue(void) const { - return id.m0; - } - - PRBool Equals(const nsHashKey *aKey) const { - return (id.Equals(((const IDKey *) aKey)->id)); - } - - nsHashKey *Clone(void) const { - return new IDKey(id); - } -}; - class nsServiceEntry { public: @@ -57,11 +34,12 @@ public: const nsCID& mClassID; nsISupports* mService; nsVector* mListeners; // nsVector + PRBool mShuttingDown; }; nsServiceEntry::nsServiceEntry(const nsCID& cid, nsISupports* service) - : mClassID(cid), mService(service), mListeners(NULL) + : mClassID(cid), mService(service), mListeners(NULL), mShuttingDown(PR_FALSE) { } @@ -216,7 +194,7 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, (void)PR_GetCurrentThread(); PR_CEnterMonitor(this); - IDKey key(aClass); + nsIDKey key(aClass); nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key); if (entry) { @@ -226,6 +204,14 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, err = entry->AddListener(shutdownListener); if (err == NS_OK) { *result = service; + + // If someone else requested the service to be shut down, + // and we just asked to get it again before it could be + // released, then cancel their shutdown request: + if (entry->mShuttingDown) { + entry->mShuttingDown = PR_FALSE; + service->AddRef(); // Released in ShutdownService + } } } } @@ -242,10 +228,8 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, err = entry->AddListener(shutdownListener); if (err == NS_OK) { mServices->Put(&key, entry); - service->AddRef(); // Add a extra ref so that the service is not freed for now. - // Should fix it later depending on Mem pressure API or some - // daemon killer thread. *result = service; + service->AddRef(); // Released in ShutdownService } else { service->Release(); @@ -261,12 +245,12 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, nsresult nsServiceManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, - nsIShutdownListener* shutdownListener) + nsIShutdownListener* shutdownListener) { nsresult err = NS_OK; PR_CEnterMonitor(this); - IDKey key(aClass); + nsIDKey key(aClass); nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key); NS_ASSERTION(entry, "service not found"); @@ -274,18 +258,12 @@ nsServiceManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, if (entry) { err = entry->RemoveListener(shutdownListener); - // XXX Is this too aggressive? Maybe we should have a memory - // pressure API that releases services if they're not in use so - // that we don't thrash.(warren) nsrefcnt cnt = service->Release(); -#if 0 - // Turns out to be too aggressive. Stanley reported that he always gets a new copy - // of service.So do not remove it. Also one cannot depend return value of Release as per COM! (sudu) if (err == NS_OK && cnt == 0) { mServices->Remove(&key); delete entry; + err = nsRepository::FreeLibraries(); } -#endif } PR_CExitMonitor(this); @@ -298,18 +276,19 @@ nsServiceManagerImpl::ShutdownService(const nsCID& aClass) nsresult err = NS_OK; PR_CEnterMonitor(this); - IDKey key(aClass); + nsIDKey key(aClass); nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key); if (entry == NULL) { err = NS_ERROR_SERVICE_NOT_FOUND; } else { - entry->mService->AddRef(); - err = entry->NotifyListeners(); - nsrefcnt cnt = entry->mService->Release(); + err = entry->NotifyListeners(); // break the cycles + entry->mShuttingDown = PR_TRUE; + nsrefcnt cnt = entry->mService->Release(); // AddRef in GetService if (err == NS_OK && cnt == 0) { mServices->Remove(&key); + delete entry; err = nsRepository::FreeLibraries(); } else diff --git a/mozilla/xpcom/ds/nsHashtable.h b/mozilla/xpcom/ds/nsHashtable.h index 930acadd304..d3ccb928a9d 100644 --- a/mozilla/xpcom/ds/nsHashtable.h +++ b/mozilla/xpcom/ds/nsHashtable.h @@ -53,4 +53,30 @@ public: void Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure = NULL); }; +//////////////////////////////////////////////////////////////////////////////// + +#include "nsID.h" + +class nsIDKey: public nsHashKey { +private: + nsID id; + +public: + nsIDKey(const nsID &aID) { + id = aID; + } + + PRUint32 HashValue(void) const { + return id.m0; + } + + PRBool Equals(const nsHashKey *aKey) const { + return (id.Equals(((const nsIDKey *) aKey)->id)); + } + + nsHashKey *Clone(void) const { + return new nsIDKey(id); + } +}; + #endif diff --git a/mozilla/xpcom/public/makefile.win b/mozilla/xpcom/public/makefile.win index ad5651803d1..562bb05ece9 100644 --- a/mozilla/xpcom/public/makefile.win +++ b/mozilla/xpcom/public/makefile.win @@ -20,7 +20,7 @@ IGNORE_MANIFEST=1 DEPTH=..\.. EXPORTS = \ - nsCOMPtr.h \ + nsCOMPtr.h \ nsAgg.h \ nsCom.h \ nsDebug.h \ @@ -41,6 +41,7 @@ EXPORTS = \ nsXPComFactory.h \ nsXPComCIID.h \ nsIEventQueueService.h \ + nsIAllocator.h \ $(NULL) MODULE = xpcom diff --git a/mozilla/xpcom/public/nsHashtable.h b/mozilla/xpcom/public/nsHashtable.h index 930acadd304..d3ccb928a9d 100644 --- a/mozilla/xpcom/public/nsHashtable.h +++ b/mozilla/xpcom/public/nsHashtable.h @@ -53,4 +53,30 @@ public: void Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure = NULL); }; +//////////////////////////////////////////////////////////////////////////////// + +#include "nsID.h" + +class nsIDKey: public nsHashKey { +private: + nsID id; + +public: + nsIDKey(const nsID &aID) { + id = aID; + } + + PRUint32 HashValue(void) const { + return id.m0; + } + + PRBool Equals(const nsHashKey *aKey) const { + return (id.Equals(((const nsIDKey *) aKey)->id)); + } + + nsHashKey *Clone(void) const { + return new nsIDKey(id); + } +}; + #endif diff --git a/mozilla/xpcom/public/nsIAllocator.h b/mozilla/xpcom/public/nsIAllocator.h new file mode 100644 index 00000000000..e6c25b8ad3e --- /dev/null +++ b/mozilla/xpcom/public/nsIAllocator.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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. + */ + +#ifndef nsIAllocator_h___ +#define nsIAllocator_h___ + +#include "nsISupports.h" + +/** + * Unlike IMalloc, this interface returns nsresults and doesn't + * implement the problematic GetSize and DidAlloc routines. + */ + +class nsIAllocator : public nsISupports { +public: + + /** + * Allocates a block of memory of a particular size. + * + * @param size - the size of the block to allocate + * @result the block of memory + */ + NS_IMETHOD_(void*) Alloc(PRUint32 size) = 0; + + /** + * Reallocates a block of memory to a new size. + * + * @param ptr - the block of memory to reallocate + * @param size - the new size + * @result the rellocated block of memory + */ + NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size) = 0; + + /** + * Frees a block of memory. + * + * @param ptr - the block of memory to free + */ + NS_IMETHOD Free(void* ptr) = 0; + + /** + * Attempts to shrink the heap. + */ + NS_IMETHOD HeapMinimize(void) = 0; + +}; + +#define NS_IALLOCATOR_IID \ +{ /* 56def700-b1b9-11d2-8177-006008119d7a */ \ + 0x56def700, \ + 0xb1b9, \ + 0x11d2, \ + {0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +// To get the global memory manager service: +#define NS_ALLOCATOR_CID \ +{ /* aafe6770-b1bb-11d2-8177-006008119d7a */ \ + 0xaafe6770, \ + 0xb1bb, \ + 0x11d2, \ + {0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +//////////////////////////////////////////////////////////////////////////////// + +#endif /* nsIAllocator_h___ */ diff --git a/mozilla/xpcom/src/makefile.win b/mozilla/xpcom/src/makefile.win index e03a0985d71..e5b0486e4f7 100644 --- a/mozilla/xpcom/src/makefile.win +++ b/mozilla/xpcom/src/makefile.win @@ -59,6 +59,7 @@ CPPSRCS = \ nsTraceRefcnt.cpp \ nsXPComFactory.cpp \ nsEventQueueService.cpp \ + nsAllocator.cpp \ $(NULL) CPP_OBJS = \ @@ -71,6 +72,7 @@ CPP_OBJS = \ .\$(OBJDIR)\nsTraceRefcnt.obj \ .\$(OBJDIR)\nsXPComFactory.obj \ .\$(OBJDIR)\nsEventQueueService.obj \ + .\$(OBJDIR)\nsAllocator.obj \ $(NULL) MODULE = xpcom diff --git a/mozilla/xpcom/src/nsAllocator.cpp b/mozilla/xpcom/src/nsAllocator.cpp new file mode 100644 index 00000000000..7b797761102 --- /dev/null +++ b/mozilla/xpcom/src/nsAllocator.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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. + */ + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of nsIAllocator using NSPR +//////////////////////////////////////////////////////////////////////////////// + +#include "nsAllocator.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIAllocatorIID, NS_IALLOCATOR_IID); + +nsAllocator::nsAllocator(nsISupports* outer) +{ + NS_INIT_AGGREGATED(outer); +} + +nsAllocator::~nsAllocator(void) +{ +} + +NS_IMPL_AGGREGATED(nsAllocator); + +NS_METHOD +nsAllocator::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIAllocatorIID) || + aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*) this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_METHOD +nsAllocator::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + if (outer && !aIID.Equals(kISupportsIID)) + return NS_NOINTERFACE; // XXX right error? + nsAllocator* mm = new nsAllocator(outer); + if (mm == NULL) + return NS_ERROR_OUT_OF_MEMORY; + mm->AddRef(); + if (aIID.Equals(kISupportsIID)) + *aInstancePtr = mm->GetInner(); + else + *aInstancePtr = mm; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_METHOD_(void*) +nsAllocator::Alloc(PRUint32 size) +{ + return PR_Malloc(size); +} + +NS_METHOD_(void*) +nsAllocator::Realloc(void* ptr, PRUint32 size) +{ + return PR_Realloc(ptr, size); +} + +NS_METHOD +nsAllocator::Free(void* ptr) +{ + PR_Free(ptr); + return NS_OK; +} + +NS_METHOD +nsAllocator::HeapMinimize(void) +{ +#ifdef XP_MAC + // This used to live in the memory allocators no Mac, but does no more + // Needs to be hooked up in the new world. +// CallCacheFlushers(0x7fffffff); +#endif + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsAllocatorFactory::nsAllocatorFactory(void) +{ +} + +nsAllocatorFactory::~nsAllocatorFactory(void) +{ +} + +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); +NS_IMPL_ISUPPORTS(nsAllocatorFactory, kIFactoryIID); + +NS_METHOD +nsAllocatorFactory::CreateInstance(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + return nsAllocator::Create(aOuter, aIID, aResult); +} + +NS_METHOD +nsAllocatorFactory::LockFactory(PRBool aLock) +{ + return NS_OK; // XXX what? +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/xpcom/src/nsAllocator.h b/mozilla/xpcom/src/nsAllocator.h new file mode 100644 index 00000000000..342f36ca3f4 --- /dev/null +++ b/mozilla/xpcom/src/nsAllocator.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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. + */ + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of nsIAllocator using NSPR +//////////////////////////////////////////////////////////////////////////////// + +#ifndef nsAllocator_h__ +#define nsAllocator_h__ + +#include "nsIAllocator.h" +#include "prmem.h" +#include "nsAgg.h" + +class nsAllocator : nsIAllocator { +public: + + /** + * Allocates a block of memory of a particular size. + * + * @param size - the size of the block to allocate + * @result the block of memory + */ + NS_IMETHOD_(void*) Alloc(PRUint32 size); + + /** + * Reallocates a block of memory to a new size. + * + * @param ptr - the block of memory to reallocate + * @param size - the new size + * @result the rellocated block of memory + */ + NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size); + + /** + * Frees a block of memory. + * + * @param ptr - the block of memory to free + */ + NS_IMETHOD Free(void* ptr); + + /** + * Attempts to shrink the heap. + */ + NS_IMETHOD HeapMinimize(void); + + //////////////////////////////////////////////////////////////////////////// + + nsAllocator(nsISupports* outer); + virtual ~nsAllocator(void); + + NS_DECL_AGGREGATED + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsIFactory.h" + +class nsAllocatorFactory : nsIFactory { +public: + NS_IMETHOD CreateInstance(nsISupports *aOuter, + REFNSIID aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + nsAllocatorFactory(void); + ~nsAllocatorFactory(void); + + NS_DECL_ISUPPORTS +}; + +//////////////////////////////////////////////////////////////////////////////// +#endif // nsAllocator_h__ diff --git a/mozilla/xpcom/src/nsRepository.cpp b/mozilla/xpcom/src/nsRepository.cpp index b696306f61c..a575abe5de9 100644 --- a/mozilla/xpcom/src/nsRepository.cpp +++ b/mozilla/xpcom/src/nsRepository.cpp @@ -86,28 +86,6 @@ public: } }; -class IDKey: public nsHashKey { -private: - nsID id; - -public: - IDKey(const nsID &aID) { - id = aID; - } - - PRUint32 HashValue(void) const { - return id.m0; - } - - PRBool Equals(const nsHashKey *aKey) const { - return (id.Equals(((const IDKey *) aKey)->id)); - } - - nsHashKey *Clone(void) const { - return new IDKey(id); - } -}; - #ifdef USE_NSREG #define USE_REGISTRY @@ -288,7 +266,7 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, PR_EnterMonitor(monitor); - IDKey key(aClass); + nsIDKey key(aClass); FactoryEntry *entry = (FactoryEntry*) factories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; @@ -452,7 +430,7 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, PR_EnterMonitor(monitor); - IDKey key(aClass); + nsIDKey key(aClass); factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL)); PR_ExitMonitor(monitor); @@ -499,7 +477,7 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, else #endif { - IDKey key(aClass); + nsIDKey key(aClass); factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary)); } @@ -530,7 +508,7 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, if (old == aFactory) { PR_EnterMonitor(monitor); - IDKey key(aClass); + nsIDKey key(aClass); FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key); delete entry; @@ -560,7 +538,7 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, delete [] buf; } - IDKey key(aClass); + nsIDKey key(aClass); FactoryEntry *old = (FactoryEntry *) factories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; diff --git a/mozilla/xpcom/src/nsServiceManager.cpp b/mozilla/xpcom/src/nsServiceManager.cpp index cc6b72efbf0..26d3fdaa264 100644 --- a/mozilla/xpcom/src/nsServiceManager.cpp +++ b/mozilla/xpcom/src/nsServiceManager.cpp @@ -21,29 +21,6 @@ #include "prcmon.h" #include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */ -// XXX move to nsID.h or nsHashtable.h? (copied from nsRepository.cpp) -class IDKey: public nsHashKey { -private: - nsID id; - -public: - IDKey(const nsID &aID) { - id = aID; - } - - PRUint32 HashValue(void) const { - return id.m0; - } - - PRBool Equals(const nsHashKey *aKey) const { - return (id.Equals(((const IDKey *) aKey)->id)); - } - - nsHashKey *Clone(void) const { - return new IDKey(id); - } -}; - class nsServiceEntry { public: @@ -57,11 +34,12 @@ public: const nsCID& mClassID; nsISupports* mService; nsVector* mListeners; // nsVector + PRBool mShuttingDown; }; nsServiceEntry::nsServiceEntry(const nsCID& cid, nsISupports* service) - : mClassID(cid), mService(service), mListeners(NULL) + : mClassID(cid), mService(service), mListeners(NULL), mShuttingDown(PR_FALSE) { } @@ -216,7 +194,7 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, (void)PR_GetCurrentThread(); PR_CEnterMonitor(this); - IDKey key(aClass); + nsIDKey key(aClass); nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key); if (entry) { @@ -226,6 +204,14 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, err = entry->AddListener(shutdownListener); if (err == NS_OK) { *result = service; + + // If someone else requested the service to be shut down, + // and we just asked to get it again before it could be + // released, then cancel their shutdown request: + if (entry->mShuttingDown) { + entry->mShuttingDown = PR_FALSE; + service->AddRef(); // Released in ShutdownService + } } } } @@ -242,10 +228,8 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, err = entry->AddListener(shutdownListener); if (err == NS_OK) { mServices->Put(&key, entry); - service->AddRef(); // Add a extra ref so that the service is not freed for now. - // Should fix it later depending on Mem pressure API or some - // daemon killer thread. *result = service; + service->AddRef(); // Released in ShutdownService } else { service->Release(); @@ -261,12 +245,12 @@ nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, nsresult nsServiceManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, - nsIShutdownListener* shutdownListener) + nsIShutdownListener* shutdownListener) { nsresult err = NS_OK; PR_CEnterMonitor(this); - IDKey key(aClass); + nsIDKey key(aClass); nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key); NS_ASSERTION(entry, "service not found"); @@ -274,18 +258,12 @@ nsServiceManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, if (entry) { err = entry->RemoveListener(shutdownListener); - // XXX Is this too aggressive? Maybe we should have a memory - // pressure API that releases services if they're not in use so - // that we don't thrash.(warren) nsrefcnt cnt = service->Release(); -#if 0 - // Turns out to be too aggressive. Stanley reported that he always gets a new copy - // of service.So do not remove it. Also one cannot depend return value of Release as per COM! (sudu) if (err == NS_OK && cnt == 0) { mServices->Remove(&key); delete entry; + err = nsRepository::FreeLibraries(); } -#endif } PR_CExitMonitor(this); @@ -298,18 +276,19 @@ nsServiceManagerImpl::ShutdownService(const nsCID& aClass) nsresult err = NS_OK; PR_CEnterMonitor(this); - IDKey key(aClass); + nsIDKey key(aClass); nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key); if (entry == NULL) { err = NS_ERROR_SERVICE_NOT_FOUND; } else { - entry->mService->AddRef(); - err = entry->NotifyListeners(); - nsrefcnt cnt = entry->mService->Release(); + err = entry->NotifyListeners(); // break the cycles + entry->mShuttingDown = PR_TRUE; + nsrefcnt cnt = entry->mService->Release(); // AddRef in GetService if (err == NS_OK && cnt == 0) { mServices->Remove(&key); + delete entry; err = nsRepository::FreeLibraries(); } else