diff options
author | mdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-18 18:27:25 +0000 |
---|---|---|
committer | mdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-18 18:27:25 +0000 |
commit | 997e22224e1062a4cd39373057a68879a1d7a3ac (patch) | |
tree | a90a9ce4272fc78f2459b1b2c78b52a3f6d4e5d3 /third_party/sqlite/src/mem5.c | |
parent | 0d683c611a18dc6ea0e99f38c73b4fb96611041f (diff) | |
download | chromium_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.c | 259 |
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 |