aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manifest16
-rw-r--r--manifest.uuid2
-rw-r--r--src/mem1.c137
-rw-r--r--src/mem2.c284
-rw-r--r--src/test_malloc.c42
5 files changed, 301 insertions, 180 deletions
diff --git a/manifest b/manifest
index 58c15ea59..1e3ffd30e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Test\sinfrastructure\sfor\sthe\snew\smemory\ssubsystem.\s(CVS\s4229)
-D 2007-08-15T19:16:43
+C Enhancements\sand\ssmoke\stesting\sof\sthe\snew\smemory\sallocation\ssubsystem.\nHave\snot\syet\scut\sit\sover\sto\sthe\score,\sthough.\s(CVS\s4230)
+D 2007-08-15T20:41:29
F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -88,8 +88,8 @@ F src/loadext.c 6c24ee62adfe7fbfb2f2dd43ff18e5534b19010f
F src/main.c f12d230c1226d3f43c1f4595af1c25ccbe3017c7
F src/malloc.c 3850ab4a2edfb190ffee353c5674ebd8c6b4ccc7
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
-F src/mem1.c ef73642a171d174cd556d0168f8edbceaf94933b
-F src/mem2.c 1f3745eae124b08706a9e582b1e75bae614d0f5a
+F src/mem1.c 6d4b9efe51242fcc63d410fb326824f1208b3d4e
+F src/mem2.c d0ba3b23da2e95bced1818ade8a8a2dc9526111c
F src/mutex.c 667dae0de95f8fb92a3ffc8c3f20c0d26115a1a6
F src/os.c e2faefbe0f5a8ca5e3b1c49ee1b5c6cfa0f0e279
F src/os.h 8eff07babf74e5bc3f895f8a6c7c294dad5ff997
@@ -133,7 +133,7 @@ F src/test_btree.c 882d59acad48bab3b1fe3daf3645059b590cfc79
F src/test_config.c 26389b032216e0fb2b544ff48a5e9101bd7b1fb4
F src/test_hexio.c 14c007252285c6dabcec4a28fcf08e9177e85178
F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
-F src/test_malloc.c 3f47498aba913d0d555e392211b9d3355f69c21b
+F src/test_malloc.c d9ba6be85f9c4a439b19f6e0a72d91c369d72c63
F src/test_md5.c d9f828765b242ff86f58cd879259c3da4eaede02
F src/test_schema.c 89c526e4b1e9a8fb540550f6ebc69242bf57d3ce
F src/test_server.c 76c0baf509abe65ca6e5c7974ab0097cfdd8b833
@@ -529,7 +529,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P af9503daf3f7703fcddad754bc1dc9e179830b6e
-R 637b616a5b01e055657d69b5613c0e1b
+P 9e506656720fb3a3205b8cc398152272ce56f6f3
+R 1bc235d902bd5b92ca3cb78565b1c6fd
U drh
-Z 56bc577909e0d6bde5f25aac7f6e7b86
+Z 15d4eec20da6957d2d37ec345d76fef8
diff --git a/manifest.uuid b/manifest.uuid
index 9adba8fb5..1b1739c4d 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-9e506656720fb3a3205b8cc398152272ce56f6f3 \ No newline at end of file
+1dad2c0a1f00596b13b02ccef664bd2346a677a4 \ No newline at end of file
diff --git a/src/mem1.c b/src/mem1.c
index 46732ca26..64b45d219 100644
--- a/src/mem1.c
+++ b/src/mem1.c
@@ -12,7 +12,7 @@
** 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 $
*/
/*
@@ -37,29 +37,42 @@
*/
#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;
/*
@@ -67,12 +80,12 @@ 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;
}
@@ -83,15 +96,15 @@ sqlite3_uint64 sqlite3_memory_used(void){
*/
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;
}
@@ -103,14 +116,14 @@ int sqlite3_memory_alarm(
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;
}
@@ -118,10 +131,10 @@ int sqlite3_memory_alarm(
** 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;
}
/*
@@ -129,11 +142,11 @@ static void sqlite3MemsysAlarm(unsigned nByte){
*/
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);
@@ -144,12 +157,12 @@ void *sqlite3_malloc(unsigned int nBytes){
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;
}
@@ -162,14 +175,14 @@ void sqlite3_free(void *pPrior){
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);
}
/*
@@ -188,9 +201,9 @@ void *sqlite3_realloc(void *pPrior, unsigned int nBytes){
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);
@@ -201,12 +214,12 @@ void *sqlite3_realloc(void *pPrior, unsigned int nBytes){
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;
}
diff --git a/src/mem2.c b/src/mem2.c
index d53861964..5135096b9 100644
--- a/src/mem2.c
+++ b/src/mem2.c
@@ -12,7 +12,7 @@
** 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 $
*/
/*
@@ -56,29 +56,89 @@
# 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 */
+};
+
/*
@@ -86,12 +146,12 @@ 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;
}
@@ -102,15 +162,15 @@ sqlite3_uint64 sqlite3_memory_used(void){
*/
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;
}
@@ -122,14 +182,14 @@ int sqlite3_memory_alarm(
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;
}
@@ -137,51 +197,13 @@ int sqlite3_memory_alarm(
** 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.
**
** This routine checks the guards at either end of the allocation and
@@ -201,7 +223,17 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
}
/*
-** 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;
@@ -210,37 +242,51 @@ void *sqlite3_malloc(unsigned int nByte){
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;
@@ -249,13 +295,13 @@ void *sqlite3_malloc(unsigned int nByte){
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;
}
@@ -268,30 +314,30 @@ void sqlite3_free(void *pPrior){
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);
}
/*
@@ -334,7 +380,7 @@ void sqlite3_memdebug_backtrace(int depth){
if( depth<0 ){ depth = 0; }
if( depth>20 ){ depth = 20; }
depth = (depth+1)&0xfe;
- backtraceLevels = depth;
+ mem.nBacktrace = depth;
}
/*
@@ -351,7 +397,7 @@ void sqlite3_memdebug_dump(const char *zFilename){
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);
@@ -364,4 +410,26 @@ void sqlite3_memdebug_dump(const char *zFilename){
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 */
diff --git a/src/test_malloc.c b/src/test_malloc.c
index 0b2ed77b4..6560fc9dd 100644
--- a/src/test_malloc.c
+++ b/src/test_malloc.c
@@ -13,7 +13,7 @@
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
-** $Id: test_malloc.c,v 1.1 2007/08/15 19:16:43 drh Exp $
+** $Id: test_malloc.c,v 1.2 2007/08/15 20:41:29 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -228,6 +228,45 @@ static int test_memdebug_dump(
/*
+** Usage: sqlite3_memdebug_fail COUNTER REPEAT
+**
+** Arrange for a simulated malloc() failure after COUNTER successes.
+** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is
+** 0 then only a single failure occurs.
+**
+** Each call to this routine overrides the prior counter value.
+** This routine returns the number of simulated failures that have
+** happened since the previous call to this routine.
+**
+** To disable simulated failures, use a COUNTER of -1.
+*/
+static int test_memdebug_fail(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int iFail;
+ int iRepeat;
+ int nFail = 0;
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "COUNTER REPEAT");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR;
+#ifdef SQLITE_MEMDEBUG
+ {
+ extern int sqlite3_memdebug_fail(int,int);
+ nFail = sqlite3_memdebug_fail(iFail, iRepeat);
+ }
+#endif
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
+ return TCL_OK;
+}
+
+
+/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_malloc_Init(Tcl_Interp *interp){
@@ -242,6 +281,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_memory_highwater", test_memory_highwater },
{ "sqlite3_memdebug_backtrace", test_memdebug_backtrace },
{ "sqlite3_memdebug_dump", test_memdebug_dump },
+ { "sqlite3_memdebug_fail", test_memdebug_fail },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){