diff options
author | drh <drh@noemail.net> | 2008-06-14 16:56:21 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2008-06-14 16:56:21 +0000 |
commit | fec00eabb3c144813164c9f04cc0fffd93c45247 (patch) | |
tree | 2f99b0ce3a38ba1b3a7ddedff7d5e66f0fa406de /src/malloc.c | |
parent | 40257ffd0a8fd292cd59769d8a1cd5873ae27fbb (diff) | |
download | sqlite-fec00eabb3c144813164c9f04cc0fffd93c45247.tar.gz sqlite-fec00eabb3c144813164c9f04cc0fffd93c45247.zip |
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
Diffstat (limited to 'src/malloc.c')
-rw-r--r-- | src/malloc.c | 254 |
1 files changed, 247 insertions, 7 deletions
diff --git a/src/malloc.c b/src/malloc.c index 55d5c76de..5916ec251 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -9,10 +9,10 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** Memory allocation functions used throughout sqlite. ** +** 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; } |