Enhancements and smoke testing of the new memory allocation subsystem.
Have not yet cut it over to the core, though. (CVS 4230) FossilOrigin-Name: 1dad2c0a1f00596b13b02ccef664bd2346a677a4
This commit is contained in:
parent
2f999a6758
commit
0e6f1546b0
16
manifest
16
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
|
||||
|
@ -1 +1 @@
|
||||
9e506656720fb3a3205b8cc398152272ce56f6f3
|
||||
1dad2c0a1f00596b13b02ccef664bd2346a677a4
|
137
src/mem1.c
137
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.
|
||||
** 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_mutex *memMutex = 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
** Current allocation and high-water mark.
|
||||
*/
|
||||
static sqlite3_uint64 nowUsed = 0;
|
||||
static sqlite3_uint64 mxUsed = 0;
|
||||
|
||||
/*
|
||||
** 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;
|
||||
}
|
||||
|
||||
|
318
src/mem2.c
318
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,93 +56,6 @@
|
||||
# define backtrace_symbols_fd(A,B,C)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Mutex to control access to the memory allocation subsystem.
|
||||
*/
|
||||
static sqlite3_mutex *memMutex = 0;
|
||||
|
||||
/*
|
||||
** Current allocation and high-water mark.
|
||||
*/
|
||||
static sqlite3_uint64 nowUsed = 0;
|
||||
static sqlite3_uint64 mxUsed = 0;
|
||||
|
||||
/*
|
||||
** 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;
|
||||
|
||||
|
||||
/*
|
||||
** Return the amount of memory currently checked out.
|
||||
*/
|
||||
sqlite3_uint64 sqlite3_memory_used(void){
|
||||
sqlite3_uint64 n;
|
||||
if( memMutex==0 ){
|
||||
memMutex = sqlite3_mutex_alloc(1);
|
||||
}
|
||||
sqlite3_mutex_enter(memMutex, 1);
|
||||
n = nowUsed;
|
||||
sqlite3_mutex_leave(memMutex);
|
||||
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_uint64 sqlite3_memory_highwater(int resetFlag){
|
||||
sqlite3_uint64 n;
|
||||
if( memMutex==0 ){
|
||||
memMutex = sqlite3_mutex_alloc(1);
|
||||
}
|
||||
sqlite3_mutex_enter(memMutex, 1);
|
||||
n = mxUsed;
|
||||
if( resetFlag ){
|
||||
mxUsed = nowUsed;
|
||||
}
|
||||
sqlite3_mutex_leave(memMutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the alarm callback
|
||||
*/
|
||||
int sqlite3_memory_alarm(
|
||||
void(*xCallback)(void *pArg, sqlite3_uint64 used, unsigned int N),
|
||||
void *pArg,
|
||||
sqlite3_uint64 iThreshold
|
||||
){
|
||||
if( memMutex==0 ){
|
||||
memMutex = sqlite3_mutex_alloc(1);
|
||||
}
|
||||
sqlite3_mutex_enter(memMutex, 1);
|
||||
alarmCallback = xCallback;
|
||||
alarmArg = pArg;
|
||||
alarmThreshold = iThreshold;
|
||||
sqlite3_mutex_leave(memMutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Trigger the alarm
|
||||
*/
|
||||
static void sqlite3MemsysAlarm(unsigned nByte){
|
||||
if( alarmCallback==0 || alarmBusy ) return;
|
||||
alarmBusy = 1;
|
||||
alarmCallback(alarmArg, nowUsed, nByte);
|
||||
alarmBusy = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Each memory allocation looks like this:
|
||||
**
|
||||
@ -171,15 +84,124 @@ struct MemBlockHdr {
|
||||
#define REARGUARD 0xE4676B53
|
||||
|
||||
/*
|
||||
** Head and tail of a linked list of all outstanding allocations
|
||||
** 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 MemBlockHdr *pFirst = 0;
|
||||
static struct MemBlockHdr *pLast = 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 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** The number of levels of backtrace to save in new allocations.
|
||||
** Return the amount of memory currently checked out.
|
||||
*/
|
||||
static int backtraceLevels = 0;
|
||||
sqlite3_uint64 sqlite3_memory_used(void){
|
||||
sqlite3_uint64 n;
|
||||
if( mem.mutex==0 ){
|
||||
mem.mutex = sqlite3_mutex_alloc(1);
|
||||
}
|
||||
sqlite3_mutex_enter(mem.mutex, 1);
|
||||
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_uint64 sqlite3_memory_highwater(int resetFlag){
|
||||
sqlite3_uint64 n;
|
||||
if( mem.mutex==0 ){
|
||||
mem.mutex = sqlite3_mutex_alloc(1);
|
||||
}
|
||||
sqlite3_mutex_enter(mem.mutex, 1);
|
||||
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_uint64 used, unsigned int N),
|
||||
void *pArg,
|
||||
sqlite3_uint64 iThreshold
|
||||
){
|
||||
if( mem.mutex==0 ){
|
||||
mem.mutex = sqlite3_mutex_alloc(1);
|
||||
}
|
||||
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( mem.alarmCallback==0 || mem.alarmBusy ) return;
|
||||
mem.alarmBusy = 1;
|
||||
mem.alarmCallback(mem.alarmArg, mem.nowUsed, nByte);
|
||||
mem.alarmBusy = 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 */
|
||||
|
@ -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++){
|
||||
|
Loading…
x
Reference in New Issue
Block a user