]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhancements and smoke testing of the new memory allocation subsystem.
authordrh <drh@noemail.net>
Wed, 15 Aug 2007 20:41:28 +0000 (20:41 +0000)
committerdrh <drh@noemail.net>
Wed, 15 Aug 2007 20:41:28 +0000 (20:41 +0000)
Have not yet cut it over to the core, though. (CVS 4230)

FossilOrigin-Name: 1dad2c0a1f00596b13b02ccef664bd2346a677a4

manifest
manifest.uuid
src/mem1.c
src/mem2.c
src/test_malloc.c

index 58c15ea59e8cb84b05e33437016f09c9078df368..1e3ffd30e1711b22b65b4ce859270d4124a78ee4 100644 (file)
--- 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
index 9adba8fb59abea86fb2b96321b0555e65eeeb036..1b1739c4de80984a841cde1e58e54acbadf199e4 100644 (file)
@@ -1 +1 @@
-9e506656720fb3a3205b8cc398152272ce56f6f3
\ No newline at end of file
+1dad2c0a1f00596b13b02ccef664bd2346a677a4
\ No newline at end of file
index 46732ca2628ad81951a95c3e26366ea8a35bc183..64b45d2196ab8e1cf4d9e3bb7d80da4a99242d45 100644 (file)
@@ -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 $
 */
 
 /*
 */
 #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;
 }
 
index d538619645f97aea2d2f0c74f561723ea9c6371b..5135096b9615fae43fe3a0144444d029c31c53fc 100644 (file)
@@ -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 $
 */
 
 /*
 # 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,50 +197,12 @@ 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.
 **
@@ -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 */
index 0b2ed77b488796ab9aedc6255288653d1a15f867..6560fc9dd6562ebdfd88f708adc9bae095f802a3 100644 (file)
@@ -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"
@@ -227,6 +227,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.
 */
@@ -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++){