/*+ −
** 2007 August 14+ −
**+ −
** The author disclaims copyright to this source code. In place of+ −
** a legal notice, here is a blessing:+ −
**+ −
** May you do good and not evil.+ −
** May you find forgiveness for yourself and forgive others.+ −
** May you share freely, never taking more than you give.+ −
**+ −
*************************************************************************+ −
** This file contains the C functions that implement a memory+ −
** allocation subsystem for use by SQLite. + −
**+ −
** $Id: mem1.cpp 1282 2008-11-13 09:31:33Z LarsPson $+ −
*/+ −
+ −
/*+ −
** This version of the memory allocator is the default. It is+ −
** used when no other memory allocator is specified using compile-time+ −
** macros.+ −
*/+ −
#if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_MEMORY_SIZE) \+ −
&& !defined(SQLITE_MMAP_HEAP_SIZE)+ −
+ −
/*+ −
** We will eventually construct multiple memory allocation subsystems+ −
** suitable for use in various contexts:+ −
**+ −
** * Normal multi-threaded builds+ −
** * Normal single-threaded builds+ −
** * Debugging builds+ −
**+ −
** This initial version is suitable for use in normal multi-threaded+ −
** builds. We envision that alternative versions will be stored in+ −
** separate source files. #ifdefs will be used to select the code from+ −
** one of the various memN.c source files for use in any given build.+ −
*/+ −
#include "sqliteInt.h"+ −
+ −
/*+ −
** All of the static variables used by this module are collected+ −
** into a single structure named "mem". This is to keep the+ −
** static variables organized and to reduce namespace pollution+ −
** when this module is combined with other in the amalgamation.+ −
*/+ −
static struct {+ −
/*+ −
** The alarm callback and its arguments. The mem.mutex lock will+ −
** be held while the callback is running. Recursive calls into+ −
** the memory subsystem are allowed, but no new callbacks will be+ −
** issued. The alarmBusy variable is set to prevent recursive+ −
** callbacks.+ −
*/+ −
sqlite3_int64 alarmThreshold;+ −
void (*alarmCallback)(void*, sqlite3_int64,int);+ −
void *alarmArg;+ −
int alarmBusy;+ −
+ −
/*+ −
** Mutex to control access to the memory allocation subsystem.+ −
*/+ −
sqlite3_mutex *mutex;+ −
+ −
/*+ −
** Current allocation and high-water mark.+ −
*/+ −
sqlite3_int64 nowUsed;+ −
sqlite3_int64 mxUsed;+ −
+ −
+ −
} mem;+ −
+ −
/*+ −
** Enter the mutex mem.mutex. Allocate it if it is not already allocated.+ −
*/+ −
static void enterMem(void){+ −
if( mem.mutex==0 ){+ −
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);+ −
}+ −
sqlite3_mutex_enter(mem.mutex);+ −
}+ −
+ −
/*+ −
** Return the amount of memory currently checked out.+ −
*/+ −
EXPORT_C sqlite3_int64 sqlite3_memory_used(void){+ −
sqlite3_int64 n;+ −
enterMem();+ −
n = mem.nowUsed;+ −
sqlite3_mutex_leave(mem.mutex); + −
return n;+ −
}+ −
+ −
/*+ −
** Return the maximum amount of memory that has ever been+ −
** checked out since either the beginning of this process+ −
** or since the most recent reset.+ −
*/+ −
EXPORT_C sqlite3_int64 sqlite3_memory_highwater(int resetFlag){+ −
sqlite3_int64 n;+ −
enterMem();+ −
n = mem.mxUsed;+ −
if( resetFlag ){+ −
mem.mxUsed = mem.nowUsed;+ −
}+ −
sqlite3_mutex_leave(mem.mutex); + −
return n;+ −
}+ −
+ −
/*+ −
** Change the alarm callback+ −
*/+ −
EXPORT_C int sqlite3_memory_alarm(+ −
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),+ −
void *pArg,+ −
sqlite3_int64 iThreshold+ −
){+ −
enterMem();+ −
mem.alarmCallback = xCallback;+ −
mem.alarmArg = pArg;+ −
mem.alarmThreshold = iThreshold;+ −
sqlite3_mutex_leave(mem.mutex);+ −
return SQLITE_OK;+ −
}+ −
+ −
/*+ −
** Trigger the alarm + −
*/+ −
static void sqlite3MemsysAlarm(int nByte){+ −
void (*xCallback)(void*,sqlite3_int64,int);+ −
sqlite3_int64 nowUsed;+ −
void *pArg;+ −
if( mem.alarmCallback==0 || mem.alarmBusy ) return;+ −
mem.alarmBusy = 1;+ −
xCallback = mem.alarmCallback;+ −
nowUsed = mem.nowUsed;+ −
pArg = mem.alarmArg;+ −
sqlite3_mutex_leave(mem.mutex);+ −
xCallback(pArg, nowUsed, nByte);+ −
sqlite3_mutex_enter(mem.mutex);+ −
mem.alarmBusy = 0;+ −
}+ −
+ −
/*+ −
** Allocate nBytes of memory+ −
*/+ −
EXPORT_C void *sqlite3_malloc(int nBytes){+ −
sqlite3_int64 *p = 0;+ −
if( nBytes>0 ){+ −
enterMem();+ −
if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){+ −
sqlite3MemsysAlarm(nBytes);+ −
}+ −
p = (sqlite3_int64*)malloc(nBytes+8);+ −
if( p==0 ){+ −
sqlite3MemsysAlarm(nBytes);+ −
p = (sqlite3_int64*)malloc(nBytes+8);+ −
}+ −
if( p ){+ −
p[0] = nBytes;+ −
p++;+ −
mem.nowUsed += nBytes;+ −
if( mem.nowUsed>mem.mxUsed ){+ −
mem.mxUsed = mem.nowUsed;+ −
}+ −
}+ −
sqlite3_mutex_leave(mem.mutex);+ −
}+ −
return (void*)p; + −
}+ −
+ −
/*+ −
** Free memory.+ −
*/+ −
EXPORT_C void sqlite3_free(void *pPrior){+ −
sqlite3_int64 *p;+ −
int nByte;+ −
if( pPrior==0 ){+ −
return;+ −
}+ −
assert( mem.mutex!=0 );+ −
p = (sqlite3_int64*)pPrior;+ −
p--;+ −
nByte = (int)*p;+ −
sqlite3_mutex_enter(mem.mutex);+ −
mem.nowUsed -= nByte;+ −
free(p);+ −
sqlite3_mutex_leave(mem.mutex); + −
}+ −
+ −
/*+ −
** Change the size of an existing memory allocation+ −
*/+ −
EXPORT_C void *sqlite3_realloc(void *pPrior, int nBytes){+ −
int nOld;+ −
sqlite3_int64 *p;+ −
if( pPrior==0 ){+ −
return sqlite3_malloc(nBytes);+ −
}+ −
if( nBytes<=0 ){+ −
sqlite3_free(pPrior);+ −
return 0;+ −
}+ −
p = (sqlite3_int64*)pPrior;+ −
p--;+ −
nOld = (int)p[0];+ −
assert( mem.mutex!=0 );+ −
sqlite3_mutex_enter(mem.mutex);+ −
if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){+ −
sqlite3MemsysAlarm(nBytes-nOld);+ −
}+ −
p = (sqlite3_int64*)realloc(p, nBytes+8);+ −
if( p==0 ){+ −
sqlite3MemsysAlarm(nBytes);+ −
p = (sqlite3_int64*)pPrior;+ −
p--;+ −
p = (sqlite3_int64*)realloc(p, nBytes+8);+ −
}+ −
if( p ){+ −
p[0] = nBytes;+ −
p++;+ −
mem.nowUsed += nBytes-nOld;+ −
if( mem.nowUsed>mem.mxUsed ){+ −
mem.mxUsed = mem.nowUsed;+ −
}+ −
}+ −
sqlite3_mutex_leave(mem.mutex);+ −
return (void*)p;+ −
}+ −
+ −
#endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */+ −