summaryrefslogtreecommitdiffstats
path: root/third_party/sqlite/src/mem5.c
diff options
context:
space:
mode:
authormdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-18 18:27:25 +0000
committermdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-18 18:27:25 +0000
commit997e22224e1062a4cd39373057a68879a1d7a3ac (patch)
treea90a9ce4272fc78f2459b1b2c78b52a3f6d4e5d3 /third_party/sqlite/src/mem5.c
parent0d683c611a18dc6ea0e99f38c73b4fb96611041f (diff)
downloadchromium_src-997e22224e1062a4cd39373057a68879a1d7a3ac.zip
chromium_src-997e22224e1062a4cd39373057a68879a1d7a3ac.tar.gz
chromium_src-997e22224e1062a4cd39373057a68879a1d7a3ac.tar.bz2
Update sqlite to version 3.6.18, porting our patches.
Hopefully this will help to address some valgrind issues. BUG=none TEST=none git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26596 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/sqlite/src/mem5.c')
-rw-r--r--third_party/sqlite/src/mem5.c259
1 files changed, 160 insertions, 99 deletions
diff --git a/third_party/sqlite/src/mem5.c b/third_party/sqlite/src/mem5.c
index 7ce28a3..3fe04e2 100644
--- a/third_party/sqlite/src/mem5.c
+++ b/third_party/sqlite/src/mem5.c
@@ -13,7 +13,7 @@
** allocation subsystem for use by SQLite.
**
** This version of the memory allocation subsystem omits all
-** use of malloc(). The SQLite user supplies a block of memory
+** use of malloc(). The application gives SQLite a block of memory
** before calling sqlite3_initialize() from which allocations
** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called,
@@ -23,42 +23,46 @@
** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
**
-** $Id: mem5.c,v 1.11 2008/07/16 12:25:32 drh Exp $
+** This memory allocator uses the following algorithm:
+**
+** 1. All memory allocations sizes are rounded up to a power of 2.
+**
+** 2. If two adjacent free blocks are the halves of a larger block,
+** then the two blocks are coalesed into the single larger block.
+**
+** 3. New memory is allocated from the first available free block.
+**
+** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
+** Concerning Dynamic Storage Allocation". Journal of the Association for
+** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
+**
+** Let n be the size of the largest allocation divided by the minimum
+** allocation size (after rounding all sizes up to a power of 2.) Let M
+** be the maximum amount of memory ever outstanding at one time. Let
+** N be the total amount of memory available for allocation. Robson
+** proved that this memory allocator will never breakdown due to
+** fragmentation as long as the following constraint holds:
+**
+** N >= M*(1 + log2(n)/2) - n + 1
+**
+** The sqlite3_status() logic tracks the maximum values of n and M so
+** that an application can, at any time, verify this constraint.
*/
#include "sqliteInt.h"
/*
** This version of the memory allocator is used only when
-** SQLITE_POW2_MEMORY_SIZE is defined.
+** SQLITE_ENABLE_MEMSYS5 is defined.
*/
#ifdef SQLITE_ENABLE_MEMSYS5
/*
-** Log2 of the minimum size of an allocation. For example, if
-** 4 then all allocations will be rounded up to at least 16 bytes.
-** If 5 then all allocations will be rounded up to at least 32 bytes.
-*/
-#ifndef SQLITE_POW2_LOGMIN
-# define SQLITE_POW2_LOGMIN 6
-#endif
-
-/*
-** Log2 of the maximum size of an allocation.
-*/
-#ifndef SQLITE_POW2_LOGMAX
-# define SQLITE_POW2_LOGMAX 20
-#endif
-#define POW2_MAX (((unsigned int)1)<<SQLITE_POW2_LOGMAX)
-
-/*
-** Number of distinct allocation sizes.
-*/
-#define NSIZE (SQLITE_POW2_LOGMAX - SQLITE_POW2_LOGMIN + 1)
-
-/*
** A minimum allocation is an instance of the following structure.
** Larger allocations are an array of these structures where the
** size of the array is a power of 2.
+**
+** The size of this object must be a power of two. That fact is
+** verified in memsys5Init().
*/
typedef struct Mem5Link Mem5Link;
struct Mem5Link {
@@ -67,16 +71,16 @@ struct Mem5Link {
};
/*
-** Maximum size of any allocation is ((1<<LOGMAX)*mem5.nAtom). Since
-** mem5.nAtom is always at least 8, this is not really a practical
-** limitation.
+** Maximum size of any allocation is ((1<<LOGMAX)*mem5.szAtom). Since
+** mem5.szAtom is always at least 8 and 32-bit integers are used,
+** it is not actually possible to reach this limit.
*/
#define LOGMAX 30
/*
** Masks used for mem5.aCtrl[] elements.
*/
-#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block relative to POW2_MIN */
+#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block */
#define CTRL_FREE 0x20 /* True if not checked out */
/*
@@ -85,18 +89,13 @@ struct Mem5Link {
** static variables organized and to reduce namespace pollution
** when this module is combined with other in the amalgamation.
*/
-static struct {
+static SQLITE_WSD struct Mem5Global {
/*
- ** The alarm callback and its arguments. The mem5.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.
+ ** Memory available for allocation
*/
- sqlite3_int64 alarmThreshold;
- void (*alarmCallback)(void*, sqlite3_int64,int);
- void *alarmArg;
- int alarmBusy;
+ int szAtom; /* Smallest possible allocation in bytes */
+ int nBlock; /* Number of szAtom sized blocks in zPool */
+ u8 *zPool; /* Memory available to be allocated */
/*
** Mutex to control access to the memory allocation subsystem.
@@ -116,7 +115,9 @@ static struct {
u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
/*
- ** Lists of free blocks of various sizes.
+ ** Lists of free blocks. aiFreelist[0] is a list of free blocks of
+ ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
+ ** and so forth.
*/
int aiFreelist[LOGMAX+1];
@@ -126,15 +127,18 @@ static struct {
*/
u8 *aCtrl;
- /*
- ** Memory available for allocation
- */
- int nAtom; /* Smallest possible allocation in bytes */
- int nBlock; /* Number of nAtom sized blocks in zPool */
- u8 *zPool;
-} mem5;
+} mem5 = { 0 };
-#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.nAtom]))
+/*
+** Access the static variable through a macro for SQLITE_OMIT_WSD
+*/
+#define mem5 GLOBAL(struct Mem5Global, mem5)
+
+/*
+** Assuming mem5.zPool is divided up into an array of Mem5Link
+** structures, return a pointer to the idx-th such lik.
+*/
+#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
/*
** Unlink the chunk at mem5.aPool[i] from list it is currently
@@ -181,12 +185,9 @@ static void memsys5Link(int i, int iLogsize){
/*
** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
** will already be held (obtained by code in malloc.c) if
-** sqlite3Config.bMemStat is true.
+** sqlite3GlobalConfig.bMemStat is true.
*/
static void memsys5Enter(void){
- if( sqlite3Config.bMemstat==0 && mem5.mutex==0 ){
- mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
- }
sqlite3_mutex_enter(mem5.mutex);
}
static void memsys5Leave(void){
@@ -201,9 +202,9 @@ static void memsys5Leave(void){
static int memsys5Size(void *p){
int iSize = 0;
if( p ){
- int i = ((u8 *)p-mem5.zPool)/mem5.nAtom;
+ int i = ((u8 *)p-mem5.zPool)/mem5.szAtom;
assert( i>=0 && i<mem5.nBlock );
- iSize = mem5.nAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
+ iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
}
return iSize;
}
@@ -229,7 +230,13 @@ static int memsys5UnlinkFirst(int iLogsize){
/*
** Return a block of memory of at least nBytes in size.
-** Return NULL if unable.
+** Return NULL if unable. Return NULL if nBytes==0.
+**
+** The caller guarantees that nByte positive.
+**
+** The caller has obtained a mutex prior to invoking this
+** routine so there is never any chance that two or more
+** threads can be in this routine at the same time.
*/
static void *memsys5MallocUnsafe(int nByte){
int i; /* Index of a mem5.aPool[] slot */
@@ -237,15 +244,24 @@ static void *memsys5MallocUnsafe(int nByte){
int iFullSz; /* Size of allocation rounded up to power of 2 */
int iLogsize; /* Log2 of iFullSz/POW2_MIN */
+ /* nByte must be a positive */
+ assert( nByte>0 );
+
/* Keep track of the maximum allocation request. Even unfulfilled
** requests are counted */
- if( nByte>mem5.maxRequest ){
+ if( (u32)nByte>mem5.maxRequest ){
mem5.maxRequest = nByte;
}
+ /* Abort if the requested allocation size is larger than the largest
+ ** power of two that we can represent using 32-bit signed integers.
+ */
+ if( nByte > 0x40000000 ){
+ return 0;
+ }
+
/* Round nByte up to the next valid power of two */
- if( nByte>POW2_MAX ) return 0;
- for(iFullSz=mem5.nAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
+ for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
** block. If not, then split a block of the next larger power of
@@ -274,7 +290,7 @@ static void *memsys5MallocUnsafe(int nByte){
if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
/* Return a pointer to the allocated memory. */
- return (void*)&mem5.zPool[i*mem5.nAtom];
+ return (void*)&mem5.zPool[i*mem5.szAtom];
}
/*
@@ -282,33 +298,33 @@ static void *memsys5MallocUnsafe(int nByte){
*/
static void memsys5FreeUnsafe(void *pOld){
u32 size, iLogsize;
- int iBlock;
+ int iBlock;
/* Set iBlock to the index of the block pointed to by pOld in
- ** the array of mem5.nAtom byte blocks pointed to by mem5.zPool.
+ ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
*/
- iBlock = ((u8 *)pOld-mem5.zPool)/mem5.nAtom;
+ iBlock = ((u8 *)pOld-mem5.zPool)/mem5.szAtom;
/* Check that the pointer pOld points to a valid, non-free block. */
assert( iBlock>=0 && iBlock<mem5.nBlock );
- assert( ((u8 *)pOld-mem5.zPool)%mem5.nAtom==0 );
+ assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 );
assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
size = 1<<iLogsize;
- assert( iBlock+size-1<mem5.nBlock );
+ assert( iBlock+size-1<(u32)mem5.nBlock );
mem5.aCtrl[iBlock] |= CTRL_FREE;
mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
assert( mem5.currentCount>0 );
- assert( mem5.currentOut>=0 );
+ assert( mem5.currentOut>=(size*mem5.szAtom) );
mem5.currentCount--;
- mem5.currentOut -= size*mem5.nAtom;
+ mem5.currentOut -= size*mem5.szAtom;
assert( mem5.currentOut>0 || mem5.currentCount==0 );
assert( mem5.currentCount>0 || mem5.currentOut==0 );
mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
- while( iLogsize<LOGMAX ){
+ while( ALWAYS(iLogsize<LOGMAX) ){
int iBuddy;
if( (iBlock>>iLogsize) & 1 ){
iBuddy = iBlock - size;
@@ -348,28 +364,36 @@ static void *memsys5Malloc(int nBytes){
/*
** Free memory.
+**
+** The outer layer memory allocator prevents this routine from
+** being called with pPrior==0.
*/
static void memsys5Free(void *pPrior){
- if( pPrior==0 ){
-assert(0);
- return;
- }
+ assert( pPrior!=0 );
memsys5Enter();
memsys5FreeUnsafe(pPrior);
memsys5Leave();
}
/*
-** Change the size of an existing memory allocation
+** Change the size of an existing memory allocation.
+**
+** The outer layer memory allocator prevents this routine from
+** being called with pPrior==0.
+**
+** nBytes is always a value obtained from a prior call to
+** memsys5Round(). Hence nBytes is always a non-negative power
+** of two. If nBytes==0 that means that an oversize allocation
+** (an allocation larger than 0x40000000) was requested and this
+** routine should return 0 without freeing pPrior.
*/
static void *memsys5Realloc(void *pPrior, int nBytes){
int nOld;
void *p;
- if( pPrior==0 ){
- return memsys5Malloc(nBytes);
- }
- if( nBytes<=0 ){
- memsys5Free(pPrior);
+ assert( pPrior!=0 );
+ assert( (nBytes&(nBytes-1))==0 );
+ assert( nBytes>=0 );
+ if( nBytes==0 ){
return 0;
}
nOld = memsys5Size(pPrior);
@@ -387,14 +411,31 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
}
/*
-** Round up a request size to the next valid allocation size.
+** Round up a request size to the next valid allocation size. If
+** the allocation is too large to be handled by this allocation system,
+** return 0.
+**
+** All allocations must be a power of two and must be expressed by a
+** 32-bit signed integer. Hence the largest allocation is 0x40000000
+** or 1073741824 bytes.
*/
static int memsys5Roundup(int n){
int iFullSz;
- for(iFullSz=mem5.nAtom; iFullSz<n; iFullSz *= 2);
+ if( n > 0x40000000 ) return 0;
+ for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
return iFullSz;
}
+/*
+** Return the ceiling of the logarithm base 2 of iValue.
+**
+** Examples: memsys5Log(1) -> 0
+** memsys5Log(2) -> 1
+** memsys5Log(4) -> 2
+** memsys5Log(5) -> 3
+** memsys5Log(8) -> 3
+** memsys5Log(9) -> 4
+*/
static int memsys5Log(int iValue){
int iLog;
for(iLog=0; (1<<iLog)<iValue; iLog++);
@@ -402,28 +443,41 @@ static int memsys5Log(int iValue){
}
/*
-** Initialize this module.
+** Initialize the memory allocator.
+**
+** This routine is not threadsafe. The caller must be holding a mutex
+** to prevent multiple threads from entering at the same time.
*/
static int memsys5Init(void *NotUsed){
- int ii;
- int nByte = sqlite3Config.nHeap;
- u8 *zByte = (u8 *)sqlite3Config.pHeap;
- int nMinLog; /* Log of minimum allocation size in bytes*/
- int iOffset;
-
- if( !zByte ){
- return SQLITE_ERROR;
- }
+ int ii; /* Loop counter */
+ int nByte; /* Number of bytes of memory available to this allocator */
+ u8 *zByte; /* Memory usable by this allocator */
+ int nMinLog; /* Log base 2 of minimum allocation size in bytes */
+ int iOffset; /* An offset into mem5.aCtrl[] */
+
+ UNUSED_PARAMETER(NotUsed);
+
+ /* For the purposes of this routine, disable the mutex */
+ mem5.mutex = 0;
+
+ /* The size of a Mem5Link object must be a power of two. Verify that
+ ** this is case.
+ */
+ assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 );
+
+ nByte = sqlite3GlobalConfig.nHeap;
+ zByte = (u8*)sqlite3GlobalConfig.pHeap;
+ assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
- nMinLog = memsys5Log(sqlite3Config.mnReq);
- mem5.nAtom = (1<<nMinLog);
- while( sizeof(Mem5Link)>mem5.nAtom ){
- mem5.nAtom = mem5.nAtom << 1;
+ nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
+ mem5.szAtom = (1<<nMinLog);
+ while( (int)sizeof(Mem5Link)>mem5.szAtom ){
+ mem5.szAtom = mem5.szAtom << 1;
}
- mem5.nBlock = (nByte / (mem5.nAtom+sizeof(u8)));
+ mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8)));
mem5.zPool = zByte;
- mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.nAtom];
+ mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom];
for(ii=0; ii<=LOGMAX; ii++){
mem5.aiFreelist[ii] = -1;
@@ -440,6 +494,11 @@ static int memsys5Init(void *NotUsed){
assert((iOffset+nAlloc)>mem5.nBlock);
}
+ /* If a mutex is required for normal operation, allocate one */
+ if( sqlite3GlobalConfig.bMemstat==0 ){
+ mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+ }
+
return SQLITE_OK;
}
@@ -447,15 +506,17 @@ static int memsys5Init(void *NotUsed){
** Deinitialize this module.
*/
static void memsys5Shutdown(void *NotUsed){
+ UNUSED_PARAMETER(NotUsed);
+ mem5.mutex = 0;
return;
}
+#ifdef SQLITE_TEST
/*
** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
void sqlite3Memsys5Dump(const char *zFilename){
-#ifdef SQLITE_DEBUG
FILE *out;
int i, j, n;
int nMinLog;
@@ -471,10 +532,10 @@ void sqlite3Memsys5Dump(const char *zFilename){
}
}
memsys5Enter();
- nMinLog = memsys5Log(mem5.nAtom);
+ nMinLog = memsys5Log(mem5.szAtom);
for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
- fprintf(out, "freelist items of size %d: %d\n", mem5.nAtom << i, n);
+ fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n);
}
fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
@@ -490,8 +551,8 @@ void sqlite3Memsys5Dump(const char *zFilename){
}else{
fclose(out);
}
-#endif
}
+#endif
/*
** This routine is the only routine in this file with external