-C Progress\stoward\simplementation\sof\ssqlite3_config()\sand\sa\srework\sof\sthe\nmutex\sand\smemory\sallocation\ssubsystems.\s\sThis\sis\san\sincremental\scheck-in.\s(CVS\s5218)
-D 2008-06-13T18:24:27
+C Continuing\sprogress\son\sthe\snew\smemory\sallocation\ssubsystem.\s\sAdded\sthe\nsqlite3_mem_methods\sstructure\sfor\sdefining\snew\smemory\sallocators\sat\nrun-time.\s(CVS\s5219)
+D 2008-06-14T16:56:22
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in dc5608df93faf4406cfd7a1c8ed9ab93d8bfbfd5
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/expr.c ecb3b23d3543427cba3e2ac12a6c6ae4bb20d39b
F src/fault.c 1f6177188edb00641673e462f3fab8cba9f7422b
F src/func.c 77a910a1ca7613d291fd0b5cba3be14c02f0dce0
-F src/global.c 8a5c66b6e61c38072c697179dbc2d708e39ddc96
+F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
F src/hash.c fd8cb06fb54c2fe7d48c9195792059a2e5be8b70
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
F src/legacy.c 8f5a2b25d9673b4004287cf2bf51dbf7d0738406
F src/loadext.c f99a75534a53e281fa2461239ee4a4b4bf6ad564
-F src/main.c 88caac737f4bdc646c7b298ebca867e9f3828208
-F src/malloc.c 12c1ae98ef1eff34b13c9eb526e0b7b479e1e820
+F src/main.c 4540ec2c0ba99a0dcb8bd114f733007958c6258e
+F src/malloc.c ed5c36588992e63ce5dccdfeb3c8071b8fb34e17
F src/md5.c 008216bbb5d34c6fbab5357aa68575ad8a31516a
-F src/mem1.c 18ca1e2543252ce13cd9c1ba67853b2d8fece3dd
-F src/mem2.c cb99d152253ae11cc2ccc4073611925e81c2212d
+F src/mem1.c 9ac005ab606a58ffe32e40edd7526375be82a008
+F src/mem2.c 10df776854bee610d5228e6184aaf3bd19f6e542
F src/mem3.c 617c2e2a72a10ecc5c01af14efc8c2596d2c2e87
F src/mem4.c 45c328ec6dcb7e8d319cb383615b5fe547ca5409
F src/mem5.c 3d2ff00c6e3bc37f5d82cd82e1a123b246fb7b39
-F src/mutex.c 1ff43a9f9a8e5a0d98ffccd77f56859d9fd9ffcf
+F src/mutex.c 639881f679d75b30813536ddf9224154321c31fb
F src/mutex.h 91292a8351b5844f7d622b0da83df4e651a8f40b
F src/mutex_os2.c b8c1231319e966875f251a7ec137bea353546b87
F src/mutex_unix.c 28588d08a2221623d66655e536880003fd5234d6
F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a
F src/select.c 669687459e7d0193c89de06c5dbed55b4a41191c
F src/shell.c a12ea645271b7876c8f080146f48e20b00d367ec
-F src/sqlite.h.in 487f5490a9677ef0c105c21a9595bb587be1da6a
+F src/sqlite.h.in 0995188c694b36d041424e1b65b6e01d1802c70b
F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3
-F src/sqliteInt.h c7b8bfb55381f62962eafd9826846c9e6e8bd429
+F src/sqliteInt.h cd66968455ee85b1ffed33bb241cbf30fe760d32
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
F src/tclsqlite.c c57e740e30bd6dda678796eed62c7f0e64689834
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P e93079be83a9df7328d9b910fcbdb762be7ec815
-R b8763d642b06205a0aac83d31a5eaad0
+P a03c5af115889f477e17187a198a7d2d40bc76bf
+R 7a7d2d9fd4f0061599821d0212d56ac9
U drh
-Z 7798430e342a4a876c2baf52ecfbbead
+Z 3478c8b21bc53c2ad4322f8aef50d224
-a03c5af115889f477e17187a198a7d2d40bc76bf
\ No newline at end of file
+f00305f4cd2f487f660f34a21c1c24a0b37c7275
\ No newline at end of file
**
** This file contains definitions of global variables and contants.
**
-** $Id: global.c,v 1.1 2008/06/13 18:24:27 drh Exp $
+** $Id: global.c,v 1.2 2008/06/14 16:56:22 drh Exp $
*/
#include "sqliteInt.h"
** The following singleton contains the global configuration for
** the SQLite library.
*/
-struct Sqlite3Config sqlite3Config;
+struct Sqlite3Config sqlite3Config = { 1, 1, 1, };
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.443 2008/06/13 18:24:27 drh Exp $
+** $Id: main.c,v 1.444 2008/06/14 16:56:22 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
*/
int sqlite3_shutdown(void){
sqlite3_os_end();
+ sqlite3MallocEnd();
sqlite3_mutex_end();
sqlite3FullInit = 0;
sqlite3IsInit = 0;
}
case SQLITE_CONFIG_MALLOC: {
/* Specify an alternative malloc implementation */
- sqlite3Config.xMalloc = va_arg(ap, void*(*)(int));
- sqlite3Config.xFree = va_arg(ap, void(*)(void*));
- sqlite3Config.xRealloc = va_arg(ap, void*(*)(void*,int));
- sqlite3Config.xMemsize = va_arg(ap, int(*)(void*));
- sqlite3Config.xRoundup = va_arg(ap, int(*)(int));
+ sqlite3Config.m = *va_arg(ap, sqlite3_mem_methods*);
break;
}
- case SQLITE_CONFIG_MEMSTATS: {
+ case SQLITE_CONFIG_MEMSTATUS: {
/* Enable or disable the malloc status collection */
sqlite3Config.bMemstat = va_arg(ap, int);
break;
** 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>
#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);
}
** 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);
** 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;
}
** 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.c,v 1.18 2008/06/13 18:24:27 drh Exp $
+** This file contains low-level memory allocation drivers for when
+** SQLite will use the standard C-library malloc/realloc/free interface
+** to obtain the memory it needs.
+**
+** This file contains implementations of the low-level memory allocation
+** routines specified in the sqlite3_mem_methods object.
+**
+** $Id: mem1.c,v 1.19 2008/06/14 16:56:22 drh Exp $
*/
#include "sqliteInt.h"
#ifdef SQLITE_SYSTEM_MALLOC
/*
-** 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.
+** Like malloc(), but remember the size of the allocation
+** so that we can find it later using sqlite3MemSize().
+**
+** For this low-level routine, we are guaranteed that nByte>0 because
+** cases of nByte<=0 will be intercepted and dealt with by higher level
+** routines.
*/
-static void enterMem(void){
- if( mem.mutex==0 ){
- mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
- }
- sqlite3_mutex_enter(mem.mutex);
+static void *sqlite3MemMalloc(int nByte){
+ sqlite3_int64 *p;
+ assert( nByte>0 );
+ nByte = (nByte+7)&~7;
+ p = malloc( nByte+8 );
+ p[0] = nByte;
+ return (void*)&p[1];
}
/*
-** Return the amount of memory currently checked out.
+** Like free() but works for allocations obtained from sqlite3MemMalloc()
+** or sqlite3MemRealloc().
+**
+** For this low-level routine, we already know that pPrior!=0 since
+** cases where pPrior==0 will have been intecepted and dealt with
+** by higher-level routines.
*/
-sqlite3_int64 sqlite3_memory_used(void){
- sqlite3_int64 n;
- enterMem();
- n = mem.nowUsed;
- sqlite3_mutex_leave(mem.mutex);
- return n;
+static void sqlite3MemFree(void *pPrior){
+ assert( pPrior!=0 );
+ sqlite3_int64 *p = (sqlite3_int64*)pPrior;
+ p--;
+ free(p);
}
/*
-** 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.
+** Like realloc(). Resize an allocation previously obtained from
+** sqlite3MemMalloc().
+**
+** For this low-level interface, we know that pPrior!=0. Cases where
+** pPrior==0 while have been intercepted by higher-level routine and
+** redirected to xMalloc. Similarly, we know that nByte>0 becauses
+** cases where nByte<=0 will have been intercepted by higher-level
+** routines and redirected to xFree.
*/
-sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
- sqlite3_int64 n;
- enterMem();
- n = mem.mxUsed;
- if( resetFlag ){
- mem.mxUsed = mem.nowUsed;
+static void *sqlite3MemRealloc(void *pPrior, int nByte){
+ sqlite3_int64 *p = (sqlite3_int64*)pPrior;
+ assert( pPrior!=0 && nByte>0 );
+ nByte = (nByte+7)&~7;
+ p = (sqlite3_int64*)pPrior;
+ p--;
+ p = realloc(p, nByte+8 );
+ if( p ){
+ p[0] = nByte;
+ p++;
}
- sqlite3_mutex_leave(mem.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
-){
- 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;
+ return (void*)p;
}
/*
-** Allocate nBytes of memory
+** Report the allocated size of a prior return from xMalloc()
+** or xRealloc().
*/
-void *sqlite3_malloc(int nBytes){
- sqlite3_int64 *p = 0;
- if( nBytes>0 ){
- enterMem();
- if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){
- sqlite3MemsysAlarm(nBytes);
- }
- if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
- p = 0;
- }else{
- p = malloc(nBytes+8);
- if( p==0 ){
- sqlite3MemsysAlarm(nBytes);
- p = 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;
+static int sqlite3MemSize(void *pPrior){
+ sqlite3_int64 *p;
+ if( pPrior==0 ) return 0;
+ p = (sqlite3_int64*)pPrior;
+ p--;
+ return p[0];
}
/*
-** Free memory.
+** Round up a request size to the next valid allocation size.
*/
-void sqlite3_free(void *pPrior){
- sqlite3_int64 *p;
- int nByte;
- if( pPrior==0 ){
- return;
- }
- assert( mem.mutex!=0 );
- p = pPrior;
- p--;
- nByte = (int)*p;
- sqlite3_mutex_enter(mem.mutex);
- mem.nowUsed -= nByte;
- free(p);
- sqlite3_mutex_leave(mem.mutex);
+static int sqlite3MemRoundup(int n){
+ return (n+7) & ~7;
}
/*
-** Return the number of bytes allocated at p.
+** Initialize this module.
*/
-int sqlite3MallocSize(void *p){
- sqlite3_int64 *pInt;
- if( !p ) return 0;
- pInt = p;
- return pInt[-1];
+static int sqlite3MemInit(void *NotUsed){
+ return SQLITE_OK;
}
/*
-** Initialize the memmory allocation subsystem.
+** Deinitialize this module.
*/
-int sqlite3MallocInit(void){
- return SQLITE_OK;
+static void sqlite3MemShutdown(void *NotUsed){
+ return;
}
/*
-** Change the size of an existing memory allocation
+** This routine is the only routine in this file with external linkage.
+**
+** Populate the low-level memory allocation function pointers in
+** sqlite3Config.m with pointers to the routines in this file.
*/
-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 = 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);
- }
- if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
- p = 0;
- }else{
- p = realloc(p, nBytes+8);
- if( p==0 ){
- sqlite3MemsysAlarm(nBytes);
- p = pPrior;
- p--;
- p = 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;
+void sqlite3MemSetDefault(void){
+ static const sqlite3_mem_methods defaultMethods = {
+ sqlite3MemMalloc,
+ sqlite3MemFree,
+ sqlite3MemRealloc,
+ sqlite3MemSize,
+ sqlite3MemRoundup,
+ sqlite3MemInit,
+ sqlite3MemShutdown,
+ 0
+ };
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
}
#endif /* SQLITE_SYSTEM_MALLOC */
** 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: mem2.c,v 1.27 2008/06/13 18:24:27 drh Exp $
+** This file contains low-level memory allocation drivers for when
+** SQLite will use the standard C-library malloc/realloc/free interface
+** to obtain the memory it needs while adding lots of additional debugging
+** information to each allocation in order to help detect and fix memory
+** leaks and memory usage errors.
+**
+** This file contains implementations of the low-level memory allocation
+** routines specified in the sqlite3_mem_methods object.
+**
+** $Id: mem2.c,v 1.28 2008/06/14 16:56:22 drh Exp $
*/
#include "sqliteInt.h"
** 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;
-
+
/*
** Head and tail of a linked list of all outstanding allocations
*/
} 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.
-*/
-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.
-*/
-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
-*/
-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;
-}
-
/*
** Given an allocation, find the MemBlockHdr for that allocation.
**
/*
** Return the number of bytes currently allocated at address p.
*/
-int sqlite3MallocSize(void *p){
+static int sqlite3MemSize(void *p){
struct MemBlockHdr *pHdr;
if( !p ){
return 0;
}
/*
-** Initialize the memmory allocation subsystem.
+** Initialize the memory allocation subsystem.
*/
-int sqlite3MallocInit(void){
+static int sqlite3MemInit(void *NotUsed){
+ mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
return SQLITE_OK;
}
+/*
+** Deinitialize the memory allocation subsystem.
+*/
+static void sqlite3MemShutdown(void *NotUsed){
+ sqlite3_mutex_free(mem.mutex);
+ mem.mutex = 0;
+}
+
+/*
+** Round up a request size to the next valid allocation size.
+*/
+static int sqlite3MemRoundup(int n){
+ return (n+7) & ~7;
+}
+
/*
** Allocate nByte bytes of memory.
*/
-void *sqlite3_malloc(int nByte){
+static void *sqlite3MemMalloc(int nByte){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
int *pInt;
void *p = 0;
int totalSize;
-
- if( nByte>0 ){
- int nReserve;
- enterMem();
- assert( mem.disallow==0 );
- if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){
- sqlite3MemsysAlarm(nByte);
- }
- nReserve = (nByte+7)&~7;
- if( nReserve/8>NCSIZE-1 ){
- mem.sizeCnt[NCSIZE-1]++;
+ int nReserve;
+ sqlite3_mutex_enter(mem.mutex);
+ assert( mem.disallow==0 );
+ nReserve = (nByte+7)&~7;
+ if( nReserve/8>NCSIZE-1 ){
+ mem.sizeCnt[NCSIZE-1]++;
+ }else{
+ mem.sizeCnt[nReserve/8]++;
+ }
+ totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
+ mem.nBacktrace*sizeof(void*) + mem.nTitle;
+ p = malloc(totalSize);
+ if( p ){
+ z = p;
+ pBt = (void**)&z[mem.nTitle];
+ pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
+ pHdr->pNext = 0;
+ pHdr->pPrev = mem.pLast;
+ if( mem.pLast ){
+ mem.pLast->pNext = pHdr;
}else{
- mem.sizeCnt[nReserve/8]++;
+ mem.pFirst = pHdr;
}
- totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
- mem.nBacktrace*sizeof(void*) + mem.nTitle;
- if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
- p = 0;
- }else{
- p = malloc(totalSize);
- if( p==0 ){
- sqlite3MemsysAlarm(nByte);
- p = malloc(totalSize);
+ mem.pLast = pHdr;
+ pHdr->iForeGuard = FOREGUARD;
+ pHdr->nBacktraceSlots = mem.nBacktrace;
+ pHdr->nTitle = mem.nTitle;
+ if( mem.nBacktrace ){
+ void *aAddr[40];
+ pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
+ memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
+ if( mem.xBacktrace ){
+ mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
}
+ }else{
+ pHdr->nBacktrace = 0;
}
- if( p ){
- z = p;
- pBt = (void**)&z[mem.nTitle];
- pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
- pHdr->pNext = 0;
- pHdr->pPrev = mem.pLast;
- if( mem.pLast ){
- mem.pLast->pNext = pHdr;
- }else{
- mem.pFirst = pHdr;
- }
- mem.pLast = pHdr;
- pHdr->iForeGuard = FOREGUARD;
- pHdr->nBacktraceSlots = mem.nBacktrace;
- pHdr->nTitle = mem.nTitle;
- if( mem.nBacktrace ){
- void *aAddr[40];
- pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
- memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
- if( mem.xBacktrace ){
- mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
- }
- }else{
- pHdr->nBacktrace = 0;
- }
- if( mem.nTitle ){
- memcpy(z, mem.zTitle, mem.nTitle);
- }
- pHdr->iSize = nByte;
- pInt = (int*)&pHdr[1];
- pInt[nReserve/sizeof(int)] = REARGUARD;
- memset(pInt, 0x65, nReserve);
- mem.nowUsed += nByte;
- if( mem.nowUsed>mem.mxUsed ){
- mem.mxUsed = mem.nowUsed;
- }
- p = (void*)pInt;
+ if( mem.nTitle ){
+ memcpy(z, mem.zTitle, mem.nTitle);
}
- sqlite3_mutex_leave(mem.mutex);
+ pHdr->iSize = nByte;
+ pInt = (int*)&pHdr[1];
+ pInt[nReserve/sizeof(int)] = REARGUARD;
+ memset(pInt, 0x65, nReserve);
+ p = (void*)pInt;
}
+ sqlite3_mutex_leave(mem.mutex);
return p;
}
/*
** Free memory.
*/
-void sqlite3_free(void *pPrior){
+static void sqlite3MemFree(void *pPrior){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
- if( pPrior==0 ){
- return;
- }
assert( mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
sqlite3_mutex_enter(mem.mutex);
- mem.nowUsed -= pHdr->iSize;
if( pHdr->pPrev ){
assert( pHdr->pPrev->pNext==pHdr );
pHdr->pPrev->pNext = pHdr->pNext;
** much more likely to break and we are much more liking to find
** the error.
*/
-void *sqlite3_realloc(void *pPrior, int nByte){
+static void *sqlite3MemRealloc(void *pPrior, int nByte){
struct MemBlockHdr *pOldHdr;
void *pNew;
- if( pPrior==0 ){
- return sqlite3_malloc(nByte);
- }
- if( nByte<=0 ){
- sqlite3_free(pPrior);
- return 0;
- }
assert( mem.disallow==0 );
pOldHdr = sqlite3MemsysGetHeader(pPrior);
- pNew = sqlite3_malloc(nByte);
+ pNew = sqlite3MemMalloc(nByte);
if( pNew ){
memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
if( nByte>pOldHdr->iSize ){
memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize);
}
- sqlite3_free(pPrior);
+ sqlite3MemFree(pPrior);
}
return pNew;
}
+
+/*
+** Populate the low-level memory allocation function pointers in
+** sqlite3Config.m with pointers to the routines in this file.
+*/
+void sqlite3MemSetDefault(void){
+ static const sqlite3_mem_methods defaultMethods = {
+ sqlite3MemMalloc,
+ sqlite3MemFree,
+ sqlite3MemRealloc,
+ sqlite3MemSize,
+ sqlite3MemRoundup,
+ sqlite3MemInit,
+ sqlite3MemShutdown,
+ 0
+ };
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
+}
+
/*
** Set the number of backtrace levels kept for each allocation.
** A value of zero turns of backtracing. The number is always rounded
*/
void sqlite3MemdebugSettitle(const char *zTitle){
int n = strlen(zTitle) + 1;
- enterMem();
+ sqlite3_mutex_enter(mem.mutex);
if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
memcpy(mem.zTitle, zTitle, n);
mem.zTitle[n] = 0;
}
/*
-** Return the number of times sqlite3_malloc() has been called.
+** Return the number of times sqlite3MemMalloc() has been called.
*/
int sqlite3MemdebugMallocCount(){
int i;
** implementation is suitable for testing.
** debugging purposes
**
-** $Id: mutex.c,v 1.18 2008/06/13 18:24:27 drh Exp $
+** $Id: mutex.c,v 1.19 2008/06/14 16:56:23 drh Exp $
*/
#include "sqliteInt.h"
** This routine deallocates a previously allocated mutex.
*/
void sqlite3_mutex_free(sqlite3_mutex *p){
- assert( p );
+ if( p==0 ) return;
assert( p->cnt==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
sqlite3_free(p);
** more than once, the behavior is undefined.
*/
void sqlite3_mutex_enter(sqlite3_mutex *p){
- assert( p );
- assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
- p->cnt++;
+ if( p ){
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ p->cnt++;
+ }
}
int sqlite3_mutex_try(sqlite3_mutex *p){
- assert( p );
- assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
- p->cnt++;
+ if( p ){
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ p->cnt++;
+ }
return SQLITE_OK;
}
** is not currently allocated. SQLite will never do either.
*/
void sqlite3_mutex_leave(sqlite3_mutex *p){
- assert( p );
- assert( sqlite3_mutex_held(p) );
- p->cnt--;
- assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ if( p ){
+ assert( sqlite3_mutex_held(p) );
+ p->cnt--;
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ }
}
/*
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
-** @(#) $Id: sqlite.h.in,v 1.326 2008/06/13 18:24:27 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.327 2008/06/14 16:56:23 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
*/
int sqlite3_config(int, ...);
+/*
+** CAPI3REF: Memory Allocation Routines {F10155}
+**
+** An instance of this object defines the interface between SQLite
+** and low-level memory allocation routines.
+**
+** This object is used in only one place in the SQLite interface.
+** A pointer to an instance of this object is the argument to
+** [sqlite3_config] when the configuration option is
+** [SQLITE_CONFIG_MALLOC]. By creating an instance of this object
+** and passing it to [sqlite3_config] during configuration, an
+** application can specify an alternative memory allocation subsystem
+** for SQLite to use for all of its dynamic memory needs.
+**
+** Note that SQLite comes with a built-in memory allocator that is
+** perfectly adequate for the overwhelming majority of applications
+** and that this object is only useful to a tiny minority of applications
+** with specialized memory allocation requirements. This object is
+** also used during testing of SQLite in order to specify an alternative
+** memory allocator that simulates memory out-of-memory conditions in
+** order to verify that SQLite recovers gracefully from such
+** conditions.
+**
+** The xMalloc, xFree, and xRealloc methods should work like the
+** malloc(), free(), and realloc() functions from the standard library.
+**
+** xSize should return the allocated size of a memory allocation
+** previously obtained from xMalloc or xRealloc. The allocated size
+** is always at least as big as the requested size but may be larger.
+**
+** The xRoundup method returns what would be the allocated size of
+** a memory allocation given a particular requested size. Most memory
+** allocators round up memory allocations at least to the next multiple
+** of 8. Some round up to a larger multiple or to a power of 2.
+**
+** The xInit method initializes the memory allocator. (For example,
+** it might allocate any require mutexes or initialize internal data
+** structures. The xShutdown method is invoked (indirectly) by
+** [sqlite3_shutdown()] and should deallocate any resources acquired
+** by xInit. The pAppData pointer is used as the only parameter to
+** xInit and xShutdown.
+*/
+typedef struct sqlite3_mem_methods sqlite3_mem_methods;
+struct sqlite3_mem_methods {
+ void *(*xMalloc)(int); /* Memory allocation function */
+ void (*xFree)(void*); /* Free a prior allocation */
+ void *(*xRealloc)(void*,int); /* Resize an allocation */
+ int (*xSize)(void*); /* Return the size of an allocation */
+ int (*xRoundup)(int); /* Round up request size to allocation size */
+ int (*xInit)(void*); /* Initialize the memory allocator */
+ void (*xShutdown)(void*); /* Deinitialize the memory allocator */
+ void *pAppData; /* Argument to xInit() and xShutdown() */
+};
+
/*
** CAPI3REF: Configuration Options {F10160}
**
** same [prepared statement] in different threads at the same time.</dd>
**
** <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd>This option takes five arguments. The first three
-** arguments are pointers to functions that emulate malloc(), free(),
-** and realloc(), respectively. The fourth argument must be a pointer to
-** a function that returns the size of a prior allocation when handed a pointer
-** to the allocation. The fifth argument is a pointer to a function that
-** returns the rounded-up size of a memory allocation given the requested
-** allocation size. This option is used to replace the default memory
-** allocator with an application-defined memory allocator.</dd>
-**
-** <dt>SQLITE_CONFIG_MEMSTATS</dt>
+** <dd>This option takes a single argument which is a pointer to an
+** instance of the [sqlite3_mem_methods] structure. The argument specifics
+** alternative low-level memory allocation routines to be used in place
+** the memory allocation routines built into SQLite.</dd>
+**
+** <dt>SQLITE_CONFIG_MEMSTATUS</dt>
** <dd>This option takes single boolean argument which enables or disables
** the collection of memory allocation statistics. When disabled, the
** following SQLite interfaces become non-operational:
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* malloc,free,realloc,memsize,roundup */
-#define SQLITE_CONFIG_MEMSTATS 5 /* boolean */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_MEMSTATUS 5 /* boolean */
/* These options are to be added later. Currently unused and undocumented. */
#define SQLITE_CONFIG_HEAP 6 /* void*, int64, min, max, tmp */
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.708 2008/06/13 18:24:27 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.709 2008/06/14 16:56:23 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
** Structure containing global configuration data for the SQLite library.
*/
struct Sqlite3Config {
- void *(*xMalloc)(int); /* Low-level malloc() */
- void *(*xRealloc)(void*,int); /* Low-level realloc() */
- void (*xFree)(void*); /* Low-level free() */
- int (*xMemsize)(void*); /* Return size of an allocation */
- int (*xRoundup)(int); /* Size of allocation given request */
+ int bMemstat; /* True to enable memory status */
+ int bCoreMutex; /* True to enable core mutexing */
+ int bFullMutex; /* True to enable full mutexing */
+ sqlite3_mem_methods m; /* Low-level memory allocation interface */
void *pHeap; /* Heap storage space */
sqlite3_int64 nHeap; /* Size of pHeap[] */
int mnReq, mxReq; /* Min and max memory request sizes */
int nTemp; /* Part of pHeap for temporary allos */
- int bMemstat; /* True to enable memory status */
- int bCoreMutex; /* True to enable core mutexing */
- int bFullMutex; /* True to enable full mutexing */
};
/*
int sqlite3IsNumber(const char*, int*, u8);
int sqlite3MallocInit(void);
-void *sqlite3MallocZero(unsigned);
-void *sqlite3DbMallocZero(sqlite3*, unsigned);
-void *sqlite3DbMallocRaw(sqlite3*, unsigned);
+void sqlite3MallocEnd(void);
+void *sqlite3Malloc(int);
+void *sqlite3MallocZero(int);
+void *sqlite3DbMallocZero(sqlite3*, int);
+void *sqlite3DbMallocRaw(sqlite3*, int);
char *sqlite3StrDup(const char*);
char *sqlite3StrNDup(const char*, int);
char *sqlite3DbStrDup(sqlite3*,const char*);
char *sqlite3DbStrNDup(sqlite3*,const char*, int);
+void *sqlite3Realloc(void*, int);
void *sqlite3DbReallocOrFree(sqlite3 *, void *, int);
void *sqlite3DbRealloc(sqlite3 *, void *, int);
int sqlite3MallocSize(void *);
+void sqlite3MemSetDefault(void);
int sqlite3IsNaN(double);