** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite.
**
-** $Id: mem1.c,v 1.2 2007/08/15 17:07:57 drh Exp $
+** $Id: mem1.c,v 1.3 2007/08/15 20:41:29 drh Exp $
*/
/*
*/
#include "sqliteInt.h"
-
-/*
-** Mutex to control access to the memory allocation subsystem.
-*/
-static sqlite3_mutex *memMutex = 0;
-
/*
-** Current allocation and high-water mark.
+** 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 sqlite3_uint64 nowUsed = 0;
-static sqlite3_uint64 mxUsed = 0;
+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_uint64 alarmThreshold;
+ void (*alarmCallback)(void*, sqlite3_uint64, unsigned);
+ void *alarmArg;
+ int alarmBusy;
+
+ /*
+ ** Mutex to control access to the memory allocation subsystem.
+ */
+ sqlite3_mutex *mutex;
+
+ /*
+ ** Current allocation and high-water mark.
+ */
+ sqlite3_uint64 nowUsed;
+ sqlite3_uint64 mxUsed;
+
+
+} mem = { /* This variable holds all of the local data */
+ ((sqlite3_uint64)1)<<63, /* alarmThreshold */
+ /* Everything else is initialized to zero */
+};
-/*
-** The alarm callback and its arguments. The memMutex 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.
-*/
-static void (*alarmCallback)(void*, sqlite3_uint64, unsigned) = 0;
-static void *alarmArg = 0;
-static sqlite3_uint64 alarmThreshold = (((sqlite3_uint64)1)<<63);
-static int alarmBusy = 0;
/*
*/
sqlite3_uint64 sqlite3_memory_used(void){
sqlite3_uint64 n;
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- n = nowUsed;
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_enter(mem.mutex, 1);
+ n = mem.nowUsed;
+ sqlite3_mutex_leave(mem.mutex);
return n;
}
*/
sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){
sqlite3_uint64 n;
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- n = mxUsed;
+ sqlite3_mutex_enter(mem.mutex, 1);
+ n = mem.mxUsed;
if( resetFlag ){
- mxUsed = nowUsed;
+ mem.mxUsed = mem.nowUsed;
}
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
return n;
}
void *pArg,
sqlite3_uint64 iThreshold
){
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- alarmCallback = xCallback;
- alarmArg = pArg;
- alarmThreshold = iThreshold;
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_enter(mem.mutex, 1);
+ mem.alarmCallback = xCallback;
+ mem.alarmArg = pArg;
+ mem.alarmThreshold = iThreshold;
+ sqlite3_mutex_leave(mem.mutex);
return SQLITE_OK;
}
** Trigger the alarm
*/
static void sqlite3MemsysAlarm(unsigned nByte){
- if( alarmCallback==0 || alarmBusy ) return;
- alarmBusy = 1;
- alarmCallback(alarmArg, nowUsed, nByte);
- alarmBusy = 0;
+ if( mem.alarmCallback==0 || mem.alarmBusy ) return;
+ mem.alarmBusy = 1;
+ mem.alarmCallback(mem.alarmArg, mem.nowUsed, nByte);
+ mem.alarmBusy = 0;
}
/*
*/
void *sqlite3_malloc(unsigned int nBytes){
sqlite3_uint64 *p;
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- if( nowUsed+nBytes>=alarmThreshold ){
+ sqlite3_mutex_enter(mem.mutex, 1);
+ if( mem.nowUsed+nBytes>=mem.alarmThreshold ){
sqlite3MemsysAlarm(nBytes);
}
p = malloc(nBytes+8);
if( p ){
p[0] = nBytes;
p++;
- nowUsed += nBytes;
- if( nowUsed>mxUsed ){
- mxUsed = nowUsed;
+ mem.nowUsed += nBytes;
+ if( mem.nowUsed>mem.mxUsed ){
+ mem.mxUsed = mem.nowUsed;
}
}
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
return (void*)p;
}
if( pPrior==0 ){
return;
}
- assert( memMutex!=0 );
+ assert( mem.mutex!=0 );
p = pPrior;
p--;
nByte = (unsigned int)*p;
- sqlite3_mutex_enter(memMutex, 1);
- nowUsed -= nByte;
+ sqlite3_mutex_enter(mem.mutex, 1);
+ mem.nowUsed -= nByte;
free(p);
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
}
/*
p = pPrior;
p--;
nOld = (unsigned int)p[0];
- assert( memMutex!=0 );
- sqlite3_mutex_enter(memMutex, 1);
- if( nowUsed+nBytes-nOld>=alarmThreshold ){
+ assert( mem.mutex!=0 );
+ sqlite3_mutex_enter(mem.mutex, 1);
+ if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){
sqlite3MemsysAlarm(nBytes-nOld);
}
p = realloc(p, nBytes+8);
if( p ){
p[0] = nBytes;
p++;
- nowUsed += nBytes-nOld;
- if( nowUsed>mxUsed ){
- mxUsed = nowUsed;
+ mem.nowUsed += nBytes-nOld;
+ if( mem.nowUsed>mem.mxUsed ){
+ mem.mxUsed = mem.nowUsed;
}
}
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
return (void*)p;
}
** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite.
**
-** $Id: mem2.c,v 1.2 2007/08/15 19:16:43 drh Exp $
+** $Id: mem2.c,v 1.3 2007/08/15 20:41:29 drh Exp $
*/
/*
# define backtrace_symbols_fd(A,B,C)
#endif
-
/*
-** Mutex to control access to the memory allocation subsystem.
+** Each memory allocation looks like this:
+**
+** ----------------------------------------------------------------
+** | backtrace pointers | MemBlockHdr | allocation | EndGuard |
+** ----------------------------------------------------------------
+**
+** The application code sees only a pointer to the allocation. We have
+** to back up from the allocation pointer to find the MemBlockHdr. The
+** MemBlockHdr tells us the size of the allocation and the number of
+** backtrace pointers. There is also a guard word at the end of the
+** MemBlockHdr.
*/
-static sqlite3_mutex *memMutex = 0;
+struct MemBlockHdr {
+ struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
+ unsigned int iSize; /* Size of this allocation */
+ unsigned short nBacktrace; /* Number of backtraces on this alloc */
+ unsigned short nBacktraceSlots; /* Available backtrace slots */
+ unsigned int iForeGuard; /* Guard word for sanity */
+};
/*
-** Current allocation and high-water mark.
+** Guard words
*/
-static sqlite3_uint64 nowUsed = 0;
-static sqlite3_uint64 mxUsed = 0;
+#define FOREGUARD 0x80F5E153
+#define REARGUARD 0xE4676B53
/*
-** The alarm callback and its arguments. The memMutex 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.
+** 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 void (*alarmCallback)(void*, sqlite3_uint64, unsigned) = 0;
-static void *alarmArg = 0;
-static sqlite3_uint64 alarmThreshold = (((sqlite3_uint64)1)<<63);
-static int alarmBusy = 0;
+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_uint64 alarmThreshold;
+ void (*alarmCallback)(void*, sqlite3_uint64, unsigned);
+ void *alarmArg;
+ int alarmBusy;
+
+ /*
+ ** Mutex to control access to the memory allocation subsystem.
+ */
+ sqlite3_mutex *mutex;
+
+ /*
+ ** Current allocation and high-water mark.
+ */
+ sqlite3_uint64 nowUsed;
+ sqlite3_uint64 mxUsed;
+
+ /*
+ ** Head and tail of a linked list of all outstanding allocations
+ */
+ struct MemBlockHdr *pFirst;
+ struct MemBlockHdr *pLast;
+
+ /*
+ ** The number of levels of backtrace to save in new allocations.
+ */
+ int nBacktrace;
+
+ /*
+ ** These values are used to simulate malloc failures. When
+ ** iFail is 1, simulate a malloc failures and reset the value
+ ** to iReset.
+ */
+ int iFail; /* Decrement and fail malloc when this is 1 */
+ int iReset; /* When malloc fails set iiFail to this value */
+ int iFailCnt; /* Number of failures */
+
+
+} mem = { /* This variable holds all of the local data */
+ ((sqlite3_uint64)1)<<63, /* alarmThreshold */
+ /* Everything else is initialized to zero */
+};
+
/*
*/
sqlite3_uint64 sqlite3_memory_used(void){
sqlite3_uint64 n;
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- n = nowUsed;
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_enter(mem.mutex, 1);
+ n = mem.nowUsed;
+ sqlite3_mutex_leave(mem.mutex);
return n;
}
*/
sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){
sqlite3_uint64 n;
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- n = mxUsed;
+ sqlite3_mutex_enter(mem.mutex, 1);
+ n = mem.mxUsed;
if( resetFlag ){
- mxUsed = nowUsed;
+ mem.mxUsed = mem.nowUsed;
}
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
return n;
}
void *pArg,
sqlite3_uint64 iThreshold
){
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- alarmCallback = xCallback;
- alarmArg = pArg;
- alarmThreshold = iThreshold;
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_enter(mem.mutex, 1);
+ mem.alarmCallback = xCallback;
+ mem.alarmArg = pArg;
+ mem.alarmThreshold = iThreshold;
+ sqlite3_mutex_leave(mem.mutex);
return SQLITE_OK;
}
** Trigger the alarm
*/
static void sqlite3MemsysAlarm(unsigned nByte){
- if( alarmCallback==0 || alarmBusy ) return;
- alarmBusy = 1;
- alarmCallback(alarmArg, nowUsed, nByte);
- alarmBusy = 0;
+ if( mem.alarmCallback==0 || mem.alarmBusy ) return;
+ mem.alarmBusy = 1;
+ mem.alarmCallback(mem.alarmArg, mem.nowUsed, nByte);
+ mem.alarmBusy = 0;
}
-/*
-** Each memory allocation looks like this:
-**
-** ----------------------------------------------------------------
-** | backtrace pointers | MemBlockHdr | allocation | EndGuard |
-** ----------------------------------------------------------------
-**
-** The application code sees only a pointer to the allocation. We have
-** to back up from the allocation pointer to find the MemBlockHdr. The
-** MemBlockHdr tells us the size of the allocation and the number of
-** backtrace pointers. There is also a guard word at the end of the
-** MemBlockHdr.
-*/
-struct MemBlockHdr {
- struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
- unsigned int iSize; /* Size of this allocation */
- unsigned short nBacktrace; /* Number of backtraces on this alloc */
- unsigned short nBacktraceSlots; /* Available backtrace slots */
- unsigned int iForeGuard; /* Guard word for sanity */
-};
-
-/*
-** Guard words
-*/
-#define FOREGUARD 0x80F5E153
-#define REARGUARD 0xE4676B53
-
-/*
-** Head and tail of a linked list of all outstanding allocations
-*/
-static struct MemBlockHdr *pFirst = 0;
-static struct MemBlockHdr *pLast = 0;
-
-/*
-** The number of levels of backtrace to save in new allocations.
-*/
-static int backtraceLevels = 0;
-
/*
** Given an allocation, find the MemBlockHdr for that allocation.
**
}
/*
-** Allocate nByte of memory
+** This routine is called once the first time a simulated memory
+** failure occurs. The sole purpose of this routine is to provide
+** a convenient place to set a debugger breakpoint when debugging
+** errors related to malloc() failures.
+*/
+static void sqlite3MemsysFailed(void){
+ mem.iFailCnt = 0;
+}
+
+/*
+** Allocate nByte bytes of memory.
*/
void *sqlite3_malloc(unsigned int nByte){
struct MemBlockHdr *pHdr;
void *p;
unsigned int totalSize;
- if( memMutex==0 ){
- memMutex = sqlite3_mutex_alloc(1);
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(1);
}
- sqlite3_mutex_enter(memMutex, 1);
- if( nowUsed+nByte>=alarmThreshold ){
+ sqlite3_mutex_enter(mem.mutex, 1);
+ if( mem.nowUsed+nByte>=mem.alarmThreshold ){
sqlite3MemsysAlarm(nByte);
}
nByte = (nByte+3)&~3;
totalSize = nByte + sizeof(*pHdr) + sizeof(unsigned int) +
- backtraceLevels*sizeof(void*);
- p = malloc(totalSize);
- if( p==0 ){
- sqlite3MemsysAlarm(nByte);
+ mem.nBacktrace*sizeof(void*);
+ if( mem.iFail>0 ){
+ if( mem.iFail==1 ){
+ p = 0;
+ mem.iFail = mem.iReset;
+ if( mem.iFailCnt==0 ){
+ sqlite3MemsysFailed(); /* A place to set a breakpoint */
+ }
+ mem.iFailCnt++;
+ }else{
+ p = malloc(totalSize);
+ mem.iFail--;
+ }
+ }else{
p = malloc(totalSize);
+ if( p==0 ){
+ sqlite3MemsysAlarm(nByte);
+ p = malloc(totalSize);
+ }
}
if( p ){
pBt = p;
- pHdr = (struct MemBlockHdr*)&pBt[backtraceLevels];
+ pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
pHdr->pNext = 0;
- pHdr->pPrev = pLast;
- if( pLast ){
- pLast->pNext = pHdr;
+ pHdr->pPrev = mem.pLast;
+ if( mem.pLast ){
+ mem.pLast->pNext = pHdr;
}else{
- pFirst = pHdr;
+ mem.pFirst = pHdr;
}
- pLast = pHdr;
+ mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
- pHdr->nBacktraceSlots = backtraceLevels;
- if( backtraceLevels ){
+ pHdr->nBacktraceSlots = mem.nBacktrace;
+ if( mem.nBacktrace ){
void *aAddr[40];
- pHdr->nBacktrace = backtrace(aAddr, backtraceLevels+1)-1;
+ pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
}else{
pHdr->nBacktrace = 0;
pInt = (unsigned int *)&pHdr[1];
pInt[nByte/sizeof(unsigned int)] = REARGUARD;
memset(pInt, 0x65, nByte);
- nowUsed += nByte;
- if( nowUsed>mxUsed ){
- mxUsed = nowUsed;
+ mem.nowUsed += nByte;
+ if( mem.nowUsed>mem.mxUsed ){
+ mem.mxUsed = mem.nowUsed;
}
p = (void*)pInt;
}
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
return p;
}
if( pPrior==0 ){
return;
}
- assert( memMutex!=0 );
+ assert( mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
- sqlite3_mutex_enter(memMutex, 1);
- nowUsed -= pHdr->iSize;
+ sqlite3_mutex_enter(mem.mutex, 1);
+ mem.nowUsed -= pHdr->iSize;
if( pHdr->pPrev ){
assert( pHdr->pPrev->pNext==pHdr );
pHdr->pPrev->pNext = pHdr->pNext;
}else{
- assert( pFirst==pHdr );
- pFirst = pHdr->pNext;
+ assert( mem.pFirst==pHdr );
+ mem.pFirst = pHdr->pNext;
}
if( pHdr->pNext ){
assert( pHdr->pNext->pPrev==pHdr );
pHdr->pNext->pPrev = pHdr->pPrev;
}else{
- assert( pLast==pHdr );
- pLast = pHdr->pPrev;
+ assert( mem.pLast==pHdr );
+ mem.pLast = pHdr->pPrev;
}
memset(pBt, 0x2b, sizeof(void*)*pHdr->nBacktrace + sizeof(*pHdr) +
pHdr->iSize + sizeof(unsigned int));
free(pBt);
- sqlite3_mutex_leave(memMutex);
+ sqlite3_mutex_leave(mem.mutex);
}
/*
if( depth<0 ){ depth = 0; }
if( depth>20 ){ depth = 20; }
depth = (depth+1)&0xfe;
- backtraceLevels = depth;
+ mem.nBacktrace = depth;
}
/*
zFilename);
return;
}
- for(pHdr=pFirst; pHdr; pHdr=pHdr->pNext){
+ for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
fprintf(out, "**** %d bytes at %p ****\n", pHdr->iSize, &pHdr[1]);
if( pHdr->nBacktrace ){
fflush(out);
fclose(out);
}
+/*
+** This routine is used to simulate malloc failures.
+**
+** After calling this routine, there will be iFail successful
+** memory allocations and then a failure. If iRepeat is true,
+** all subsequent memory allocations will fail. If iRepeat is
+** false, only a single allocation will fail.
+**
+** Each call to this routine overrides the previous. To disable
+** the simulated allocation failure mechanism, set iFail to -1.
+**
+** This routine returns the number of simulated failures that have
+** occurred since the previous call.
+*/
+int sqlite3_memdebug_fail(int iFail, int iRepeat){
+ int n = mem.iFailCnt;
+ mem.iFail = iFail+1;
+ mem.iReset = iRepeat;
+ mem.iFailCnt = 0;
+ return n;
+}
+
#endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */