Bug 267767 - Make XPCOM memory management functions frozen exports. r=darin sr=shaver

git-svn-id: svn://10.0.0.236/trunk@165320 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bsmedberg%covad.net
2004-11-12 19:26:37 +00:00
parent e9003390d6
commit 80c1808b53
17 changed files with 480 additions and 504 deletions

View File

@@ -41,6 +41,7 @@
#include "nsILocalFile.h"
#ifdef STANDALONE_PROFILEDIRSERVICE
#define MOZILLA_STRICT_API
#include "nsEmbedString.h"
#else
#include "nsString.h"

View File

@@ -41,6 +41,7 @@
#include "nsProfileStringTypes.h"
#include "nsProfileLock.h"
#include "nsCOMPtr.h"
#if defined(XP_MAC) || defined(XP_MACOSX)
#include <Processes.h>

View File

@@ -50,6 +50,7 @@
*/
#ifdef STANDALONE_PROFILEDIRSERVICE
#define MOZILLA_STRICT_API
#include "nsEmbedString.h"
typedef nsEmbedString nsString;

View File

@@ -42,6 +42,10 @@
* nsIMemory: interface to allocate and deallocate memory. Also provides
* for notifications in low-memory situations.
*
* The frozen exported symbols NS_Alloc, NS_Realloc, and NS_Free
* provide a more efficient way to access XPCOM memory allocation. Using
* those symbols is preferred to using the methods on this interface.
*
* A client that wishes to be notified of low memory situations (for
* example, because the client maintains a large memory cache that
* could be released when memory is tight) should register with the

View File

@@ -35,14 +35,22 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsXPCOM.h"
#include "nsMemoryImpl.h"
#include "prmem.h"
#include "nsAlgorithm.h"
#include "nsIServiceManager.h"
#include "nsIObserverService.h"
#include "nsAutoLock.h"
#include "nsIThread.h"
#include "nsIEventQueueService.h"
#include "nsIObserverService.h"
#include "nsIRunnable.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsIThread.h"
#include "prmem.h"
#include "plevent.h"
#include "nsAlgorithm.h"
#include "nsAutoLock.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#if defined(XP_WIN)
@@ -56,216 +64,6 @@
#undef NS_MEMORY_FLUSHER_THREAD
#endif
//----------------------------------------------------------------------
#if defined(XDEBUG_waterson)
#define NS_TEST_MEMORY_FLUSHER
#endif
/**
* A runnable that is used to periodically check the status
* of the system, determine if too much memory is in use,
* and if so, trigger a "memory flush".
*/
class MemoryFlusher : public nsIRunnable
{
protected:
nsMemoryImpl* mMemoryImpl; // WEAK, it owns us.
PRBool mRunning;
PRIntervalTime mTimeout;
PRLock* mLock;
PRCondVar* mCVar;
MemoryFlusher(nsMemoryImpl* aMemoryImpl);
enum {
kInitialTimeout = 60 /*seconds*/
};
private:
~MemoryFlusher();
public:
/**
* Create a memory flusher.
* @param aResult the memory flusher
* @param aMemoryImpl the owning nsMemoryImpl object
* @return NS_OK if the memory flusher was created successfully
*/
static nsresult
Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl);
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
/**
* Stop the memory flusher.
*/
nsresult Stop();
};
MemoryFlusher::MemoryFlusher(nsMemoryImpl* aMemoryImpl)
: mMemoryImpl(aMemoryImpl),
mRunning(PR_FALSE),
mTimeout(PR_SecondsToInterval(kInitialTimeout)),
mLock(nsnull),
mCVar(nsnull)
{
}
MemoryFlusher::~MemoryFlusher()
{
if (mLock)
PR_DestroyLock(mLock);
if (mCVar)
PR_DestroyCondVar(mCVar);
}
nsresult
MemoryFlusher::Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl)
{
MemoryFlusher* result = new MemoryFlusher(aMemoryImpl);
if (! result)
return NS_ERROR_OUT_OF_MEMORY;
do {
if ((result->mLock = PR_NewLock()) == nsnull)
break;
if ((result->mCVar = PR_NewCondVar(result->mLock)) == nsnull)
break;
NS_ADDREF(*aResult = result);
return NS_OK;
} while (0);
// Something bad happened if we get here...
delete result;
return NS_ERROR_OUT_OF_MEMORY;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(MemoryFlusher, nsIRunnable)
NS_IMETHODIMP
MemoryFlusher::Run()
{
nsresult rv;
mRunning = PR_TRUE;
while (1) {
PRStatus status;
{
nsAutoLock l(mLock);
if (! mRunning) {
rv = NS_OK;
break;
}
status = PR_WaitCondVar(mCVar, mTimeout);
}
if (status != PR_SUCCESS) {
rv = NS_ERROR_FAILURE;
break;
}
if (! mRunning) {
rv = NS_OK;
break;
}
PRBool isLowMemory;
rv = mMemoryImpl->IsLowMemory(&isLowMemory);
if (NS_FAILED(rv))
break;
#ifdef NS_TEST_MEMORY_FLUSHER
// Fire the flusher *every* time
isLowMemory = PR_TRUE;
#endif
if (isLowMemory) {
mMemoryImpl->FlushMemory(NS_LITERAL_STRING("low-memory").get(), PR_FALSE);
}
}
mRunning = PR_FALSE;
return rv;
}
nsresult
MemoryFlusher::Stop()
{
if (mRunning) {
nsAutoLock l(mLock);
mRunning = PR_FALSE;
PR_NotifyCondVar(mCVar);
}
return NS_OK;
}
//----------------------------------------------------------------------
nsMemoryImpl* gMemory = nsnull;
NS_IMPL_THREADSAFE_ISUPPORTS1(nsMemoryImpl, nsIMemory)
NS_METHOD
nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
NS_ENSURE_PROPER_AGGREGATION(outer, aIID);
if (gMemory && NS_SUCCEEDED(gMemory->QueryInterface(aIID, aInstancePtr)))
return NS_OK;
nsMemoryImpl* mm = new nsMemoryImpl();
if (mm == NULL)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
do {
rv = mm->QueryInterface(aIID, aInstancePtr);
if (NS_FAILED(rv))
break;
rv = NS_ERROR_OUT_OF_MEMORY;
mm->mFlushLock = PR_NewLock();
if (! mm->mFlushLock)
break;
rv = NS_OK;
} while (0);
if (NS_FAILED(rv))
delete mm;
return rv;
}
nsMemoryImpl::nsMemoryImpl()
: mFlusher(nsnull),
mFlushLock(nsnull),
mIsFlushing(PR_FALSE)
{
}
nsMemoryImpl::~nsMemoryImpl()
{
if (mFlushLock)
PR_DestroyLock(mFlushLock);
}
////////////////////////////////////////////////////////////////////////////////
// Define NS_OUT_OF_MEMORY_TESTER if you want to force memory failures
@@ -316,35 +114,66 @@ reallocator(void* ptr, PRSize size, PRUint32& counter, PRUint32 max)
#endif // NS_OUT_OF_MEMORY_TESTER
////////////////////////////////////////////////////////////////////////////////
#if defined(XDEBUG_waterson)
#define NS_TEST_MEMORY_FLUSHER
#endif
NS_IMETHODIMP_(void *)
#ifdef NS_MEMORY_FLUSHER_THREAD
/**
* A runnable that is used to periodically check the status
* of the system, determine if too much memory is in use,
* and if so, trigger a "memory flush".
*/
class MemoryFlusher : public nsIRunnable
{
public:
// We don't use the generic macros because we are a special static object
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aResult);
NS_IMETHOD_(nsrefcnt) AddRef(void) { return 1; }
NS_IMETHOD_(nsrefcnt) Release(void) { return 1; }
NS_DECL_NSIRUNNABLE
nsresult Init();
void StopAndJoin();
private:
static PRBool sRunning;
static PRIntervalTime sTimeout;
static PRLock* sLock;
static PRCondVar* sCVar;
static nsIThread* sThread;
enum {
kInitialTimeout = 60 /*seconds*/
};
};
static MemoryFlusher sGlobalMemoryFlusher;
#endif // NS_MEMORY_FLUSHER_THREAD
static nsMemoryImpl sGlobalMemory;
NS_IMPL_QUERY_INTERFACE1(nsMemoryImpl, nsIMemory)
NS_IMETHODIMP_(void*)
nsMemoryImpl::Alloc(PRSize size)
{
NS_ASSERTION(size, "nsMemoryImpl::Alloc of 0");
void* result = MALLOC1(size);
if (! result) {
// Request an asynchronous flush
FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE);
}
return result;
return NS_Alloc(size);
}
NS_IMETHODIMP_(void *)
nsMemoryImpl::Realloc(void * ptr, PRSize size)
NS_IMETHODIMP_(void*)
nsMemoryImpl::Realloc(void* ptr, PRSize size)
{
void* result = REALLOC1(ptr, size);
if (! result) {
// Request an asynchronous flush
FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE);
}
return result;
return NS_Realloc(ptr, size);
}
NS_IMETHODIMP_(void)
nsMemoryImpl::Free(void * ptr)
nsMemoryImpl::Free(void* ptr)
{
PR_Free(ptr);
NS_Free(ptr);
}
NS_IMETHODIMP
@@ -397,6 +226,38 @@ nsMemoryImpl::IsLowMemory(PRBool *result)
return NS_OK;
}
nsresult
nsMemoryImpl::Startup()
{
#ifdef NS_MEMORY_FLUSHER_THREAD
sFlushLock = PR_NewLock();
if (!sFlushLock) return NS_ERROR_FAILURE;
return sGlobalMemoryFlusher.Init();
#else
return NS_OK;
#endif
}
void
nsMemoryImpl::Shutdown()
{
#ifdef NS_MEMORY_FLUSHER_THREAD
sGlobalMemoryFlusher.StopAndJoin();
#endif
if (sFlushLock) PR_DestroyLock(sFlushLock);
sFlushLock = nsnull;
}
nsresult
nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void **aResult)
{
NS_ENSURE_NO_AGGREGATION(outer);
return sGlobalMemory.QueryInterface(aIID, aResult);
}
nsresult
nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate)
{
@@ -427,18 +288,18 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate)
{
// Are we already flushing?
nsAutoLock l(mFlushLock);
if (mIsFlushing)
nsAutoLock l(sFlushLock);
if (sIsFlushing)
return NS_OK;
// Well, we are now!
mIsFlushing = PR_TRUE;
sIsFlushing = PR_TRUE;
}
// Run the flushers immediately if we can; otherwise, proxy to the
// UI thread an run 'em asynchronously.
if (aImmediate) {
rv = RunFlushers(this, aReason);
rv = RunFlushers(aReason);
}
else {
nsCOMPtr<nsIEventQueueService> eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
@@ -446,10 +307,10 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate)
nsCOMPtr<nsIEventQueue> eq;
rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq));
if (NS_SUCCEEDED(rv)) {
PL_InitEvent(&mFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent);
mFlushEvent.mReason = aReason;
PL_InitEvent(&sFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent);
sFlushEvent.mReason = aReason;
rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &mFlushEvent));
rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &sFlushEvent));
}
}
}
@@ -458,17 +319,17 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate)
}
nsresult
nsMemoryImpl::RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason)
nsMemoryImpl::RunFlushers(const PRUnichar* aReason)
{
nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
if (os) {
os->NotifyObservers(aSelf, "memory-pressure", aReason);
os->NotifyObservers(this, "memory-pressure", aReason);
}
{
// Done flushing
nsAutoLock l(aSelf->mFlushLock);
aSelf->mIsFlushing = PR_FALSE;
nsAutoLock l(sFlushLock);
sIsFlushing = PR_FALSE;
}
return NS_OK;
@@ -477,10 +338,9 @@ nsMemoryImpl::RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason)
void*
nsMemoryImpl::HandleFlushEvent(PLEvent* aEvent)
{
nsMemoryImpl* self = NS_STATIC_CAST(nsMemoryImpl*, PL_GetEventOwner(aEvent));
FlushEvent* event = NS_REINTERPRET_CAST(FlushEvent*, aEvent);
RunFlushers(self, event->mReason);
sGlobalMemory.RunFlushers(event->mReason);
return 0;
}
@@ -490,59 +350,159 @@ nsMemoryImpl::DestroyFlushEvent(PLEvent* aEvent)
// no-op, since mEvent is a member of nsMemoryImpl
}
static void
EnsureGlobalMemoryService()
PRLock*
nsMemoryImpl::sFlushLock;
PRBool
nsMemoryImpl::sIsFlushing = PR_FALSE;
nsMemoryImpl::FlushEvent
nsMemoryImpl::sFlushEvent;
extern "C" NS_EXPORT void*
NS_Alloc(PRSize size)
{
if (gMemory) return;
nsresult rv = nsMemoryImpl::Create(nsnull, NS_GET_IID(nsIMemory), (void**)&gMemory);
NS_ASSERTION(NS_SUCCEEDED(rv), "nsMemoryImpl::Create failed");
NS_ASSERTION(gMemory, "improper xpcom initialization");
NS_ASSERTION(size, "NS_Alloc of size 0");
void* result = MALLOC1(size);
if (! result) {
// Request an asynchronous flush
sGlobalMemory.FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE);
}
return result;
}
nsresult
nsMemoryImpl::Startup()
extern "C" NS_EXPORT void*
NS_Realloc(void* ptr, PRSize size)
{
EnsureGlobalMemoryService();
if (! gMemory)
return NS_ERROR_FAILURE;
NS_ASSERTION(size, "NS_Realloc of size 0");
void* result = REALLOC1(ptr, size);
if (! result) {
// Request an asynchronous flush
sGlobalMemory.FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE);
}
return result;
}
extern "C" NS_EXPORT void
NS_Free(void* ptr)
{
PR_Free(ptr);
}
#ifdef NS_MEMORY_FLUSHER_THREAD
NS_IMPL_QUERY_INTERFACE1(MemoryFlusher, nsIRunnable);
NS_IMETHODIMP
MemoryFlusher::Run()
{
nsresult rv;
// Create and start a memory flusher thread
rv = MemoryFlusher::Create(&gMemory->mFlusher, gMemory);
if (NS_FAILED(rv)) return rv;
sRunning = PR_TRUE;
rv = NS_NewThread(getter_AddRefs(gMemory->mFlusherThread),
gMemory->mFlusher,
0, /* XXX use default stack size? */
PR_JOINABLE_THREAD);
while (1) {
PRStatus status;
if (NS_FAILED(rv)) return rv;
#endif
{
nsAutoLock l(sLock);
if (! sRunning) {
rv = NS_OK;
break;
}
return NS_OK;
}
nsresult
nsMemoryImpl::Shutdown()
{
if (gMemory) {
#ifdef NS_MEMORY_FLUSHER_THREAD
if (gMemory->mFlusher) {
// Stop the runnable...
gMemory->mFlusher->Stop();
NS_RELEASE(gMemory->mFlusher);
// ...and wait for the thread to exit
if (gMemory->mFlusherThread)
gMemory->mFlusherThread->Join();
status = PR_WaitCondVar(sCVar, sTimeout);
}
if (status != PR_SUCCESS) {
rv = NS_ERROR_FAILURE;
break;
}
if (! sRunning) {
rv = NS_OK;
break;
}
PRBool isLowMemory;
rv = sGlobalMemory.IsLowMemory(&isLowMemory);
if (NS_FAILED(rv))
break;
#ifdef NS_TEST_MEMORY_FLUSHER
// Fire the flusher *every* time
isLowMemory = PR_TRUE;
#endif
NS_RELEASE(gMemory);
gMemory = nsnull;
if (isLowMemory) {
sGlobalMemory.FlushMemory(NS_LITERAL_STRING("low-memory").get(), PR_FALSE);
}
}
return NS_OK;
sRunning = PR_FALSE;
return rv;
}
nsresult
MemoryFlusher::Init()
{
sTimeout = PR_SecondsToInterval(kInitialTimeout);
sLock = PR_NewLock();
if (!sLock) return NS_ERROR_FAILURE;
sCVar = PR_NewCondVar(sLock);
if (!sCVar) return NS_ERROR_FAILURE;
return NS_NewThread(&sThread,
this,
0, /* XXX use default stack size? */
PR_JOINABLE_THREAD);
}
void
MemoryFlusher::StopAndJoin()
{
if (sRunning) {
{
nsAutoLock l(sLock);
sRunning = PR_FALSE;
PR_NotifyCondVar(sCVar);
}
if (sThread)
sThread->Join();
}
NS_IF_RELEASE(sThread);
if (sLock)
PR_DestroyLock(sLock);
if (sCVar)
PR_DestroyCondVar(sCVar);
}
PRBool
MemoryFlusher::sRunning;
PRIntervalTime
MemoryFlusher::sTimeout;
PRLock*
MemoryFlusher::sLock;
PRCondVar*
MemoryFlusher::sCVar;
nsIThread*
MemoryFlusher::sThread;
#endif // NS_MEMORY_FLUSHER_THREAD
nsresult
NS_GetMemoryManager(nsIMemory* *result)
{
return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**) result);
}

View File

@@ -38,54 +38,45 @@
#ifndef nsMemoryImpl_h__
#define nsMemoryImpl_h__
#include "nsMemory.h"
#include "nsISupportsArray.h"
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsCOMPtr.h"
#include "nsIMemory.h"
#include "prlock.h"
#include "plevent.h"
struct PRLock;
class MemoryFlusher;
// nsMemoryImpl is a static object. We can do this because it doesn't have
// a constructor/destructor or any instance members. Please don't add
// instance member variables, only static member variables.
class nsMemoryImpl : public nsIMemory
{
public:
NS_DECL_ISUPPORTS
// We don't use the generic macros because we are a special static object
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aResult);
NS_IMETHOD_(nsrefcnt) AddRef(void) { return 1; }
NS_IMETHOD_(nsrefcnt) Release(void) { return 1; }
NS_DECL_NSIMEMORY
nsMemoryImpl();
static NS_HIDDEN_(nsresult) Startup();
static NS_HIDDEN_(void) Shutdown();
static NS_METHOD Create(nsISupports* outer,
const nsIID& aIID, void **aResult);
nsresult FlushMemory(const PRUnichar* aReason, PRBool aImmediate);
// called from xpcom initialization/finalization:
static nsresult Startup();
static nsresult Shutdown();
static NS_METHOD
Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
private:
~nsMemoryImpl();
NS_HIDDEN_(nsresult) FlushMemory(const PRUnichar* aReason, PRBool aImmediate);
protected:
MemoryFlusher* mFlusher;
nsCOMPtr<nsIThread> mFlusherThread;
PRLock* mFlushLock;
PRBool mIsFlushing;
struct FlushEvent {
PLEvent mEvent;
const PRUnichar* mReason;
};
FlushEvent mFlushEvent;
NS_HIDDEN_(nsresult) RunFlushers(const PRUnichar* aReason);
static NS_HIDDEN_(void*) PR_CALLBACK HandleFlushEvent(PLEvent* aEvent);
static NS_HIDDEN_(void) PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent);
static nsresult RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason);
static PRLock* sFlushLock;
static PRBool sIsFlushing;
static void* PR_CALLBACK HandleFlushEvent(PLEvent* aEvent);
static void PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent);
static FlushEvent sFlushEvent;
};
#endif // nsMemoryImpl_h__

View File

@@ -50,6 +50,9 @@
# define NS_NewNativeLocalFile NS_NewNativeLocalFile_P
# define NS_GetDebug NS_GetDebug_P
# define NS_GetTraceRefcnt NS_GetTraceRefcnt_P
# define NS_Alloc NS_Alloc_P
# define NS_Realloc NS_Realloc_P
# define NS_Free NS_Free_P
#endif
#include "nscore.h"
@@ -208,6 +211,52 @@ NS_NewNativeLocalFile(const nsACString &path,
PRBool followLinks,
nsILocalFile* *result);
/**
* Allocates a block of memory of a particular size. If the memory cannot
* be allocated (because of an out-of-memory condition), null is returned.
*
* @status FROZEN
*
* @param size The size of the block to allocate
* @result The block of memory
* @note This function is thread-safe.
*/
extern "C" NS_COM void*
NS_Alloc(PRSize size);
/**
* Reallocates a block of memory to a new size.
*
* @status FROZEN
*
* @param ptr The block of memory to reallocate. This block must originally
have been allocated by NS_Alloc or NS_Realloc
* @param size The new size. If 0, frees the block like NS_Free
* @result The reallocated block of memory
* @note This function is thread-safe.
*
* If ptr is null, this function behaves like NS_Alloc.
* If s is the size of the block to which ptr points, the first min(s, size)
* bytes of ptr's block are copied to the new block. If the allocation
* succeeds, ptr is freed and a pointer to the new block is returned. If the
* allocation fails, ptr is not freed and null is returned. The returned
* value may be the same as ptr.
*/
extern "C" NS_COM void*
NS_Realloc(void* ptr, PRSize size);
/**
* Frees a block of memory. Null is a permissible value, in which case no
* action is taken.
*
* @status FROZEN
*
* @param ptr The block of memory to free. This block must originally have
* been allocated by NS_Alloc or NS_Realloc
* @note This function is thread-safe.
*/
extern "C" NS_COM void
NS_Free(void* ptr);
extern "C" NS_COM nsresult
NS_GetDebug(nsIDebug* *result);

View File

@@ -43,11 +43,11 @@
#ifndef MOZILLA_STRICT_API
# define NS_RegisterXPCOMExitRoutine NS_RegisterXPCOMExitRoutine_P
# define NS_UnregisterXPCOMExitRoutine NS_UnregisterXPCOMExitRoutine_P
# define NS_GetFrozenFunctions NS_GetFrozenFunctions_P
#endif
#include "nscore.h"
#include "nsXPCOM.h"
#include "nsStringAPI.h"
class nsStringContainer;
class nsCStringContainer;
@@ -111,8 +111,12 @@ typedef nsresult (* CStringSetDataFunc)(nsACString&, const char*, PRUint32);
typedef nsresult (* CStringSetDataRangeFunc)(nsACString&, PRUint32, PRUint32, const char*, PRUint32);
typedef nsresult (* CStringCopyFunc)(nsACString &, const nsACString &);
typedef nsresult (* CStringToUTF16)(const nsACString &, PRUint32, const nsAString &);
typedef nsresult (* UTF16ToCString)(const nsAString &, PRUint32, const nsACString &);
typedef nsresult (* CStringToUTF16)(const nsACString &, nsCStringEncoding, nsAString &);
typedef nsresult (* UTF16ToCString)(const nsAString &, nsCStringEncoding, nsACString &);
typedef void* (* AllocFunc)(PRSize size);
typedef void* (* ReallocFunc)(void* ptr, PRSize size);
typedef void (* FreeFunc)(void* ptr);
// PRIVATE
typedef nsresult (* RegisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine, PRUint32 priority);
@@ -155,6 +159,9 @@ typedef struct XPCOMFunctions{
UTF16ToCString utf16ToCString;
StringCloneDataFunc stringCloneData;
CStringCloneDataFunc cstringCloneData;
AllocFunc allocFunc;
ReallocFunc reallocFunc;
FreeFunc freeFunc;
} XPCOMFunctions;

View File

@@ -384,21 +384,6 @@ static const nsModuleComponentInfo components[] = {
const int components_length = sizeof(components) / sizeof(components[0]);
// gMemory will be freed during shutdown.
static nsIMemory* gMemory = nsnull;
nsresult NS_COM NS_GetMemoryManager(nsIMemory* *result)
{
nsresult rv = NS_OK;
if (!gMemory)
{
rv = nsMemoryImpl::Create(nsnull,
NS_GET_IID(nsIMemory),
(void**)&gMemory);
}
NS_IF_ADDREF(*result = gMemory);
return rv;
}
// gDebug will be freed during shutdown.
static nsIDebug* gDebug = nsnull;
nsresult NS_COM NS_GetDebug(nsIDebug** result)
@@ -856,7 +841,6 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr)
EmptyEnumeratorImpl::Shutdown();
nsMemoryImpl::Shutdown();
NS_IF_RELEASE(gMemory);
nsThread::Shutdown();
NS_PurgeAtomTable();
@@ -876,65 +860,3 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr)
return NS_OK;
}
#define GET_FUNC(_tag, _decl, _name) \
functions->_tag = (_decl) PR_FindSymbol(xpcomLib, _name); \
if (!functions->_tag) goto end
nsresult NS_COM PR_CALLBACK
NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* libraryPath)
{
if (!functions)
return NS_ERROR_OUT_OF_MEMORY;
if (functions->version != XPCOM_GLUE_VERSION)
return NS_ERROR_FAILURE;
PRLibrary *xpcomLib = PR_LoadLibrary(libraryPath);
if (!xpcomLib)
return NS_ERROR_FAILURE;
nsresult rv = NS_ERROR_FAILURE;
GET_FUNC(init, InitFunc, "NS_InitXPCOM2");
GET_FUNC(shutdown, ShutdownFunc, "NS_ShutdownXPCOM");
GET_FUNC(getServiceManager, GetServiceManagerFunc, "NS_GetServiceManager");
GET_FUNC(getComponentManager, GetComponentManagerFunc, "NS_GetComponentManager");
GET_FUNC(getComponentRegistrar, GetComponentRegistrarFunc, "NS_GetComponentRegistrar");
GET_FUNC(getMemoryManager, GetMemoryManagerFunc, "NS_GetMemoryManager");
GET_FUNC(newLocalFile, NewLocalFileFunc, "NS_NewLocalFile");
GET_FUNC(newNativeLocalFile, NewNativeLocalFileFunc, "NS_NewNativeLocalFile");
GET_FUNC(registerExitRoutine, RegisterXPCOMExitRoutineFunc, "NS_RegisterXPCOMExitRoutine");
GET_FUNC(unregisterExitRoutine, UnregisterXPCOMExitRoutineFunc, "NS_UnregisterXPCOMExitRoutine");
// these functions were added post 1.4 (need to check size of |functions|)
if (functions->size > offsetof(XPCOMFunctions, getTraceRefcnt)) {
GET_FUNC(getDebug, GetDebugFunc, "NS_GetDebug");
GET_FUNC(getTraceRefcnt, GetTraceRefcntFunc, "NS_GetTraceRefcnt");
}
// these functions were added post 1.6 (need to check size of |functions|)
if (functions->size > offsetof(XPCOMFunctions, cstringCloneData)) {
GET_FUNC(stringContainerInit, StringContainerInitFunc, "NS_StringContainerInit");
GET_FUNC(stringContainerFinish, StringContainerFinishFunc, "NS_StringContainerFinish");
GET_FUNC(stringGetData, StringGetDataFunc, "NS_StringGetData");
GET_FUNC(stringSetData, StringSetDataFunc, "NS_StringSetData");
GET_FUNC(stringSetDataRange, StringSetDataRangeFunc, "NS_StringSetDataRange");
GET_FUNC(stringCopy, StringCopyFunc, "NS_StringCopy");
GET_FUNC(cstringContainerInit, CStringContainerInitFunc, "NS_CStringContainerInit");
GET_FUNC(cstringContainerFinish, CStringContainerFinishFunc, "NS_CStringContainerFinish");
GET_FUNC(cstringGetData, CStringGetDataFunc, "NS_CStringGetData");
GET_FUNC(cstringSetData, CStringSetDataFunc, "NS_CStringSetData");
GET_FUNC(cstringSetDataRange, CStringSetDataRangeFunc, "NS_CStringSetDataRange");
GET_FUNC(cstringCopy, CStringCopyFunc, "NS_CStringCopy");
GET_FUNC(cstringToUTF16, CStringToUTF16, "NS_CStringToUTF16");
GET_FUNC(utf16ToCString, UTF16ToCString, "NS_UTF16ToCString");
GET_FUNC(stringCloneData, StringCloneDataFunc, "NS_StringCloneData");
GET_FUNC(cstringCloneData, CStringCloneDataFunc, "NS_CStringCloneData");
}
rv = NS_OK;
end:
PR_UnloadLibrary(xpcomLib); // the library is refcnt'ed above by the caller.
return rv;
}

View File

@@ -48,7 +48,9 @@ DIRS = standalone
MODULE = xpcom
LIBRARY_NAME = xpcomglue_s
REQUIRES = $(NULL)
REQUIRES = \
string \
$(NULL)
LOCAL_INCLUDES = \
-I$(srcdir)/../build \

View File

@@ -40,89 +40,25 @@
#include "nsXPCOMPrivate.h"
#include "nsDebug.h"
#include "nsISupportsUtils.h"
static nsIMemory* gMemory = nsnull;
static NS_METHOD FreeGlobalMemory(void)
{
NS_IF_RELEASE(gMemory);
return NS_OK;
}
#define ENSURE_ALLOCATOR \
(gMemory ? PR_TRUE : (PRBool)(SetupGlobalMemory() != nsnull))
static nsIMemory*
SetupGlobalMemory()
{
NS_ASSERTION(!gMemory, "bad call");
NS_GetMemoryManager(&gMemory);
NS_ASSERTION(gMemory, "can't get memory manager!");
NS_RegisterXPCOMExitRoutine(FreeGlobalMemory, 0);
return gMemory;
}
#ifdef XPCOM_GLUE
nsresult GlueStartupMemory()
{
NS_ASSERTION(!gMemory, "bad call");
NS_GetMemoryManager(&gMemory);
NS_ASSERTION(gMemory, "can't get memory manager!");
return NS_OK;
}
void GlueShutdownMemory()
{
NS_IF_RELEASE(gMemory);
}
#endif
#include "nsCOMPtr.h"
////////////////////////////////////////////////////////////////////////////////
// nsMemory static helper routines
NS_COM_GLUE void*
nsMemory::Alloc(PRSize size)
{
if (!ENSURE_ALLOCATOR)
return nsnull;
return gMemory->Alloc(size);
}
NS_COM_GLUE void*
nsMemory::Realloc(void* ptr, PRSize size)
{
if (!ENSURE_ALLOCATOR)
return nsnull;
return gMemory->Realloc(ptr, size);
}
NS_COM_GLUE void
nsMemory::Free(void* ptr)
{
if (!ENSURE_ALLOCATOR)
return;
gMemory->Free(ptr);
}
NS_COM_GLUE nsresult
nsMemory::HeapMinimize(PRBool aImmediate)
{
if (!ENSURE_ALLOCATOR)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMemory> mem;
nsresult rv = NS_GetMemoryManager(getter_AddRefs(mem));
NS_ENSURE_SUCCESS(rv, rv);
return gMemory->HeapMinimize(aImmediate);
return mem->HeapMinimize(aImmediate);
}
NS_COM_GLUE void*
nsMemory::Clone(const void* ptr, PRSize size)
{
if (!ENSURE_ALLOCATOR)
return nsnull;
void* newPtr = gMemory->Alloc(size);
void* newPtr = NS_Alloc(size);
if (newPtr)
memcpy(newPtr, ptr, size);
return newPtr;
@@ -131,12 +67,11 @@ nsMemory::Clone(const void* ptr, PRSize size)
NS_COM_GLUE nsIMemory*
nsMemory::GetGlobalMemoryService()
{
if (!ENSURE_ALLOCATOR)
return nsnull;
nsIMemory* mem;
nsresult rv = NS_GetMemoryManager(&mem);
if (NS_FAILED(rv)) return nsnull;
nsIMemory* result = gMemory;
NS_IF_ADDREF(result);
return result;
return mem;
}
//----------------------------------------------------------------------

View File

@@ -38,6 +38,7 @@
#ifndef nsMemory_h__
#define nsMemory_h__
#include "nsXPCOM.h"
#include "nsIMemory.h"
#define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1"
@@ -63,11 +64,17 @@
class nsMemory
{
public:
static NS_COM_GLUE void* Alloc(size_t size);
static NS_COM_GLUE void* Realloc(void* ptr, size_t size);
static NS_COM_GLUE void Free(void* ptr);
static NS_HIDDEN_(void*) Alloc(size_t size)
{ return NS_Alloc(size); }
static NS_HIDDEN_(void*) Realloc(void* ptr, PRSize size)
{ return NS_Realloc(ptr, size); }
static NS_HIDDEN_(void) Free(void* ptr)
{ NS_Free(ptr); }
static NS_COM_GLUE nsresult HeapMinimize(PRBool aImmediate);
static NS_COM_GLUE void* Clone(const void* ptr, size_t size);
static NS_COM_GLUE void* Clone(const void* ptr, PRSize size);
static NS_COM_GLUE nsIMemory* GetGlobalMemoryService(); // AddRefs
};
@@ -105,7 +112,7 @@ public:
PRInt32 iter_ = PRInt32(size); \
while (--iter_ >= 0) \
freeFunc((array)[iter_]); \
nsMemory::Free((array)); \
NS_Free((array)); \
PR_END_MACRO
// convenience macros for commonly used calls. mmmmm. syntactic sugar.
@@ -121,7 +128,7 @@ public:
* @param array The array to be freed.
*/
#define NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(size, array) \
NS_FREE_XPCOM_POINTER_ARRAY((size), (array), nsMemory::Free)
NS_FREE_XPCOM_POINTER_ARRAY((size), (array), NS_Free)
/**
* Macro to free an array of pointers to nsISupports (or classes

View File

@@ -39,7 +39,6 @@
#include "nsXPCOMGlue.h"
#include "nspr.h"
#include "nsMemory.h"
#include "nsDebug.h"
#include "nsIServiceManager.h"
#include "nsGREDirServiceProvider.h"
@@ -54,9 +53,7 @@
void GRE_AddGREToEnvironment();
// functions provided by nsMemory.cpp and nsDebug.cpp
nsresult GlueStartupMemory();
void GlueShutdownMemory();
// functions provided by nsDebug.cpp
nsresult GlueStartupDebug();
void GlueShutdownDebug();
@@ -152,13 +149,6 @@ nsresult XPCOMGlueStartup(const char* xpcomFile)
if (NS_FAILED(rv))
goto bail;
// startup the nsMemory
rv = GlueStartupMemory();
if (NS_FAILED(rv)) {
GlueShutdownDebug();
goto bail;
}
GRE_AddGREToEnvironment();
return NS_OK;
@@ -177,8 +167,6 @@ nsresult XPCOMGlueShutdown()
return NS_OK;
#else
GlueShutdownMemory();
GlueShutdownDebug();
if (xpcomLib) {
@@ -411,7 +399,7 @@ NS_CStringCopy(nsACString &aDest, const nsACString &aSrc)
}
extern "C" NS_COM nsresult
NS_CStringToUTF16(const nsACString &aSrc, PRUint32 aSrcEncoding, nsAString &aDest)
NS_CStringToUTF16(const nsACString &aSrc, nsCStringEncoding aSrcEncoding, nsAString &aDest)
{
if (!xpcomFunctions.cstringToUTF16)
return NS_ERROR_NOT_INITIALIZED;
@@ -419,13 +407,36 @@ NS_CStringToUTF16(const nsACString &aSrc, PRUint32 aSrcEncoding, nsAString &aDes
}
extern "C" NS_COM nsresult
NS_UTF16ToCString(const nsAString &aSrc, PRUint32 aDestEncoding, nsACString &aDest)
NS_UTF16ToCString(const nsAString &aSrc, nsCStringEncoding aDestEncoding, nsACString &aDest)
{
if (!xpcomFunctions.utf16ToCString)
return NS_ERROR_NOT_INITIALIZED;
return xpcomFunctions.utf16ToCString(aSrc, aDestEncoding, aDest);
}
extern "C" NS_COM void*
NS_Alloc(PRSize size)
{
if (!xpcomFunctions.allocFunc)
return nsnull;
return xpcomFunctions.allocFunc(size);
}
extern "C" NS_COM void*
NS_Realloc(void* ptr, PRSize size)
{
if (!xpcomFunctions.reallocFunc)
return nsnull;
return xpcomFunctions.reallocFunc(ptr, size);
}
extern "C" NS_COM void
NS_Free(void* ptr)
{
if (xpcomFunctions.freeFunc)
xpcomFunctions.freeFunc(ptr);
}
#endif // #ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING

View File

@@ -40,6 +40,10 @@
#ifndef nsEmbedString_h___
#define nsEmbedString_h___
#ifndef MOZILLA_STRICT_API
#error nsEmbedString requires defining MOZILLA_STRICT_API
#endif
#include "nsStringAPI.h"
class nsEmbedString : public nsStringContainer

View File

@@ -637,14 +637,14 @@ NS_UTF16ToCString(const nsAString &aSource, nsCStringEncoding aDestEncoding,
* internal definition of these classes from nsAString.h in the Mozilla tree.
*/
#ifndef _IMPL_NS_STRINGAPI
#ifdef MOZILLA_STRICT_API
#define nsAString_external nsAString
#define nsACString_external nsACString
#endif
class nsAString_external
{
#ifndef _IMPL_NS_STRINGAPI
#ifdef MOZILLA_STRICT_API
public:
typedef PRUnichar char_type;
@@ -718,7 +718,7 @@ public:
NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); }
#endif // _IMPL_NS_STRINGAPI
#endif // MOZILLA_STRICT_API
private:
void *v;
@@ -726,7 +726,7 @@ private:
class nsACString_external
{
#ifndef _IMPL_NS_STRINGAPI
#ifdef MOZILLA_STRICT_API
public:
typedef char char_type;
@@ -800,7 +800,7 @@ public:
NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); }
#endif // _IMPL_NS_STRINGAPI
#endif // MOZILLA_STRICT_API
private:
void *v;

View File

@@ -19,6 +19,7 @@
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
* Benjamin Smedberg <bsmedberg@covad.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -38,6 +39,70 @@
#include "nsXPCOMPrivate.h"
#include "nsStringAPI.h"
#include <string.h>
static const XPCOMFunctions kFrozenFunctions = {
XPCOM_GLUE_VERSION,
sizeof(XPCOMFunctions),
&NS_InitXPCOM2_P,
&NS_ShutdownXPCOM_P,
&NS_GetServiceManager_P,
&NS_GetComponentManager_P,
&NS_GetComponentRegistrar_P,
&NS_GetMemoryManager_P,
&NS_NewLocalFile_P,
&NS_NewNativeLocalFile_P,
&NS_RegisterXPCOMExitRoutine_P,
&NS_UnregisterXPCOMExitRoutine_P,
// these functions were added post 1.4
&NS_GetDebug_P,
&NS_GetTraceRefcnt_P,
// these functions were added post 1.6
&NS_StringContainerInit,
&NS_StringContainerFinish,
&NS_StringGetData,
&NS_StringSetData,
&NS_StringSetDataRange,
&NS_StringCopy,
&NS_CStringContainerInit,
&NS_CStringContainerFinish,
&NS_CStringGetData,
&NS_CStringSetData,
&NS_CStringSetDataRange,
&NS_CStringCopy,
&NS_CStringToUTF16,
&NS_UTF16ToCString,
&NS_StringCloneData,
&NS_CStringCloneData,
// these functions were added post 1.7 (Firefox 1.0)
&NS_Alloc_P,
&NS_Realloc_P,
&NS_Free_P
};
extern "C" NS_EXPORT nsresult
NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* /* libraryPath */)
{
if (!functions)
return NS_ERROR_OUT_OF_MEMORY;
if (functions->version != XPCOM_GLUE_VERSION)
return NS_ERROR_FAILURE;
PRUint32 size = functions->size;
if (size > sizeof(XPCOMFunctions))
size = sizeof(XPCOMFunctions);
size -= offsetof(XPCOMFunctions, init);
memcpy(&functions->init, &kFrozenFunctions.init, size);
return NS_OK;
}
/*
* Stubs for nsXPCOM.h
*/
@@ -136,9 +201,23 @@ NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine)
return NS_UnregisterXPCOMExitRoutine_P(exitRoutine);
}
#undef NS_GetFrozenFunctions
extern "C" NS_EXPORT nsresult
NS_GetFrozenFunctions(XPCOMFunctions *entryPoints, const char* libraryPath)
#undef NS_Alloc
extern "C" NS_EXPORT void*
NS_Alloc(PRSize size)
{
return NS_GetFrozenFunctions_P(entryPoints, libraryPath);
return NS_Alloc_P(size);
}
#undef NS_Realloc
extern "C" NS_EXPORT void*
NS_Realloc(void* ptr, PRSize size)
{
return NS_Realloc_P(ptr, size);
}
#undef NS_Free
extern "C" NS_EXPORT void
NS_Free(void* ptr)
{
NS_Free_P(ptr);
}

View File

@@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#define MOZILLA_STRICT_API
#include <stdio.h>
#include "nsStringAPI.h"
#include "nsCRT.h"