nsMemoryImpl.cpp revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* 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.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#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 "nsString.h"
#if defined(XP_WIN)
#include <windows.h>
#define NS_MEMORY_FLUSHER_THREAD
#include <MacMemory.h>
#define NS_MEMORY_FLUSHER_THREAD
#else
// Need to implement the nsIMemory::IsLowMemory() predicate
#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:
enum {
};
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
/**
* Stop the memory flusher.
*/
};
{
}
{
if (mLock)
if (mCVar)
}
{
if (! result)
return NS_ERROR_OUT_OF_MEMORY;
do {
break;
break;
return NS_OK;
} while (0);
// Something bad happened if we get here...
delete result;
return NS_ERROR_OUT_OF_MEMORY;
}
MemoryFlusher::Run()
{
while (1) {
{
nsAutoLock l(mLock);
if (! mRunning) {
break;
}
}
if (status != PR_SUCCESS) {
break;
}
if (! mRunning) {
break;
}
break;
#ifdef NS_TEST_MEMORY_FLUSHER
// Fire the flusher *every* time
#endif
if (isLowMemory) {
}
}
return rv;
}
{
if (mRunning) {
nsAutoLock l(mLock);
}
return NS_OK;
}
//----------------------------------------------------------------------
{
return NS_OK;
return NS_ERROR_OUT_OF_MEMORY;
do {
break;
if (! mm->mFlushLock)
break;
} while (0);
delete mm;
return rv;
}
{
}
{
if (mFlushLock)
}
////////////////////////////////////////////////////////////////////////////////
// Define NS_OUT_OF_MEMORY_TESTER if you want to force memory failures
#ifdef DEBUG_xwarren
#define NS_OUT_OF_MEMORY_TESTER
#endif
#ifdef NS_OUT_OF_MEMORY_TESTER
// flush memory one in this number of times:
#define NS_FLUSH_FREQUENCY 100000
// fail allocation one in this number of flushes:
#define NS_FAIL_FREQUENCY 10
PRUint32 gFlushFreq = 0;
static void*
{
counter = 0;
NS_ASSERTION(0, "about to fail allocation... watch out");
return nsnull;
}
}
static void*
{
counter = 0;
NS_ASSERTION(0, "about to fail reallocation... watch out");
return nsnull;
}
}
#else
#define REALLOC1(p, s) PR_Realloc(p, s)
#endif // NS_OUT_OF_MEMORY_TESTER
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP_(void *)
{
if (! result) {
// Request an asynchronous flush
}
return result;
}
NS_IMETHODIMP_(void *)
{
if (! result) {
// Request an asynchronous flush
}
return result;
}
NS_IMETHODIMP_(void)
{
}
{
}
{
#if defined(XP_WIN)
long totalSpace, contiguousSpace;
// this call measures how much memory would be available if the OS
// purged. Despite the name, it does not purge (that happens
// automatically when heap space is low).
{
NS_WARNING("Found that heap mem is low");
return NS_OK;
}
// see how much temp mem is available (since our allocators allocate 1Mb chunks
// in temp mem. We don't use TempMaxMem() (to get contig space) here, because it
// compacts the application heap, so can be slow.
long totalTempSpace = ::TempFreeMem();
{
NS_WARNING("Found that temp mem is low");
return NS_OK;
}
#else
#endif
return NS_OK;
}
{
if (aImmediate) {
// They've asked us to run the flusher *immediately*. We've
// got to be on the UI main thread for us to be able to do
// that...are we?
if (NS_SUCCEEDED(rv)) {
if (NS_SUCCEEDED(rv)) {
}
}
if (! isOnUIThread) {
NS_ERROR("can't synchronously flush memory: not on UI thread");
return NS_ERROR_FAILURE;
}
}
{
// Are we already flushing?
nsAutoLock l(mFlushLock);
if (mIsFlushing)
return NS_OK;
// Well, we are now!
}
// Run the flushers immediately if we can; otherwise, proxy to the
// UI thread an run 'em asynchronously.
if (aImmediate) {
}
else {
if (eqs) {
if (NS_SUCCEEDED(rv)) {
}
}
}
return rv;
}
{
if (os) {
}
{
// Done flushing
}
return NS_OK;
}
void*
{
return 0;
}
void
{
// no-op, since mEvent is a member of nsMemoryImpl
}
static void
{
if (gMemory) return;
}
{
if (! gMemory)
return NS_ERROR_FAILURE;
#ifdef NS_MEMORY_FLUSHER_THREAD
// Create and start a memory flusher thread
0, /* XXX use default stack size? */
#endif
return NS_OK;
}
{
if (gMemory) {
#ifdef NS_MEMORY_FLUSHER_THREAD
// Stop the runnable...
// ...and wait for the thread to exit
if (gMemory->mFlusherThread)
}
#endif
}
return NS_OK;
}