Continuing progress on the new memory allocation subsystem. Added the

sqlite3_mem_methods structure for defining new memory allocators at
run-time. (CVS 5219)

FossilOrigin-Name: f00305f4cd2f487f660f34a21c1c24a0b37c7275
This commit is contained in:
drh
2008-06-14 16:56:21 +00:00
parent 40257ffd0a
commit fec00eabb3
10 changed files with 559 additions and 447 deletions
+247 -7
View File
@@ -9,10 +9,10 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** Memory allocation functions used throughout sqlite.
**
**
** $Id: malloc.c,v 1.15 2008/03/26 18:34:43 danielk1977 Exp $
** $Id: malloc.c,v 1.16 2008/06/14 16:56:22 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@@ -67,12 +67,252 @@ int sqlite3_release_memory(int n){
#endif
}
/*
** State information local to the memory allocation subsystem.
*/
static struct {
sqlite3_mutex *mutex; /* Mutex to serialize access */
/*
** The alarm callback and its arguments. The mem0.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;
/*
** Performance statistics
*/
sqlite3_int64 nowUsed; /* Main memory currently in use */
sqlite3_int64 mxUsed; /* Highwater mark for nowUsed */
int mxReq; /* maximum request size for main or page-cache mem */
} mem0;
/*
** Initialize the memory allocation subsystem.
*/
int sqlite3MallocInit(void){
if( sqlite3Config.m.xMalloc==0 ){
sqlite3MemSetDefault();
}
memset(&mem0, 0, sizeof(mem0));
if( sqlite3Config.bMemstat && sqlite3Config.bCoreMutex ){
mem0.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
}
return sqlite3Config.m.xInit(sqlite3Config.m.pAppData);
}
/*
** Deinitialize the memory allocation subsystem.
*/
void sqlite3MallocEnd(void){
sqlite3Config.m.xShutdown(sqlite3Config.m.pAppData);
}
/*
** Return the amount of memory currently checked out.
*/
sqlite3_int64 sqlite3_memory_used(void){
sqlite3_int64 n;
sqlite3_mutex_enter(mem0.mutex);
n = mem0.nowUsed;
sqlite3_mutex_leave(mem0.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.
*/
sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
sqlite3_int64 n;
sqlite3_mutex_enter(mem0.mutex);
n = mem0.mxUsed;
if( resetFlag ){
mem0.mxUsed = mem0.nowUsed;
}
sqlite3_mutex_leave(mem0.mutex);
return n;
}
/*
** Change the alarm callback
*/
int sqlite3_memory_alarm(
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
void *pArg,
sqlite3_int64 iThreshold
){
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmCallback = xCallback;
mem0.alarmArg = pArg;
mem0.alarmThreshold = iThreshold;
sqlite3_mutex_leave(mem0.mutex);
return SQLITE_OK;
}
/*
** Trigger the alarm
*/
static void sqlite3MallocAlarm(int nByte){
void (*xCallback)(void*,sqlite3_int64,int);
sqlite3_int64 nowUsed;
void *pArg;
if( mem0.alarmCallback==0 || mem0.alarmBusy ) return;
mem0.alarmBusy = 1;
xCallback = mem0.alarmCallback;
nowUsed = mem0.nowUsed;
pArg = mem0.alarmArg;
sqlite3_mutex_leave(mem0.mutex);
xCallback(pArg, nowUsed, nByte);
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmBusy = 0;
}
/*
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
void *sqlite3Malloc(int n){
void *p;
int nFull;
if( n<=0 ){
return 0;
}else if( sqlite3Config.bMemstat ){
nFull = sqlite3Config.m.xRoundup(n);
sqlite3_mutex_enter(mem0.mutex);
if( n>mem0.mxReq ) mem0.mxReq = n;
if( mem0.alarmCallback!=0 && mem0.nowUsed+nFull>=mem0.alarmThreshold ){
sqlite3MallocAlarm(nFull);
}
if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
p = 0;
}else{
p = sqlite3Config.m.xMalloc(nFull);
if( p==0 ){
sqlite3MallocAlarm(nFull);
p = malloc(nFull);
}
}
if( p ){
mem0.nowUsed += nFull;
if( mem0.nowUsed>mem0.mxUsed ){
mem0.mxUsed = mem0.nowUsed;
}
}
sqlite3_mutex_leave(mem0.mutex);
}else{
p = sqlite3Config.m.xMalloc(n);
}
return p;
}
/*
** This version of the memory allocation is for use by the application.
** First make sure the memory subsystem is initialized, then do the
** allocation.
*/
void *sqlite3_malloc(int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
return sqlite3Malloc(n);
}
/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
int sqlite3MallocSize(void *p){
return sqlite3Config.m.xSize(p);
}
/*
** Free memory previously obtained from sqlite3Malloc().
*/
void sqlite3_free(void *p){
if( p==0 ) return;
if( sqlite3Config.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
mem0.nowUsed -= sqlite3MallocSize(p);
sqlite3Config.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3Config.m.xFree(p);
}
}
/*
** Change the size of an existing memory allocation
*/
void *sqlite3Realloc(void *pOld, int nBytes){
int nOld, nNew;
void *pNew;
if( pOld==0 ){
return sqlite3Malloc(nBytes);
}
if( nBytes<=0 ){
sqlite3_free(pOld);
return 0;
}
nOld = sqlite3MallocSize(pOld);
if( sqlite3Config.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
if( nBytes>mem0.mxReq ) mem0.mxReq = nBytes;
nNew = sqlite3Config.m.xRoundup(nBytes);
if( nOld==nNew ){
pNew = pOld;
}else{
if( mem0.nowUsed+nNew-nOld>=mem0.alarmThreshold ){
sqlite3MallocAlarm(nNew-nOld);
}
if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
pNew = 0;
}else{
pNew = sqlite3Config.m.xRealloc(pOld, nNew);
if( pNew==0 ){
sqlite3MallocAlarm(nBytes);
pNew = sqlite3Config.m.xRealloc(pOld, nNew);
}
}
if( pNew ){
mem0.nowUsed += nNew-nOld;
if( mem0.nowUsed>mem0.mxUsed ){
mem0.mxUsed = mem0.nowUsed;
}
}
}
sqlite3_mutex_leave(mem0.mutex);
}else{
pNew = sqlite3Config.m.xRealloc(pOld, nBytes);
}
return pNew;
}
/*
** The public interface to sqlite3Realloc. Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
void *sqlite3_realloc(void *pOld, int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
return sqlite3Realloc(pOld, n);
}
/*
** Allocate and zero memory.
*/
void *sqlite3MallocZero(unsigned n){
void *p = sqlite3_malloc(n);
void *sqlite3MallocZero(int n){
void *p = sqlite3Malloc(n);
if( p ){
memset(p, 0, n);
}
@@ -83,7 +323,7 @@ void *sqlite3MallocZero(unsigned n){
** Allocate and zero memory. If the allocation fails, make
** the mallocFailed flag in the connection pointer.
*/
void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){
void *sqlite3DbMallocZero(sqlite3 *db, int n){
void *p = sqlite3DbMallocRaw(db, n);
if( p ){
memset(p, 0, n);
@@ -95,10 +335,10 @@ void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){
** Allocate and zero memory. If the allocation fails, make
** the mallocFailed flag in the connection pointer.
*/
void *sqlite3DbMallocRaw(sqlite3 *db, unsigned n){
void *sqlite3DbMallocRaw(sqlite3 *db, int n){
void *p = 0;
if( !db || db->mallocFailed==0 ){
p = sqlite3_malloc(n);
p = sqlite3Malloc(n);
if( !p && db ){
db->mallocFailed = 1;
}