aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mem5.c88
1 files changed, 71 insertions, 17 deletions
diff --git a/src/mem5.c b/src/mem5.c
index f9389e9e9..02f665e9c 100644
--- a/src/mem5.c
+++ b/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,7 +23,30 @@
** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
**
-** $Id: mem5.c,v 1.19 2008/11/19 16:52:44 danielk1977 Exp $
+** This memory allocator uses the following algorithm:
+**
+** 1. All memory allocations sizes are rounded up to a power of 2.
+**
+** 2. To adjacent and aligned free blocks are coalesced into a single
+** block of the next larger size.
+**
+** 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"
@@ -37,6 +60,9 @@
** 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 {
@@ -46,8 +72,8 @@ 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.
+** mem5.nAtom is always at least 8 and 32-bit integers are used,
+** it is not actually possible to reach this limit.
*/
#define LOGMAX 30
@@ -69,7 +95,7 @@ static SQLITE_WSD struct Mem5Global {
*/
int nAtom; /* Smallest possible allocation in bytes */
int nBlock; /* Number of nAtom sized blocks in zPool */
- u8 *zPool;
+ u8 *zPool; /* Memory available to be allocated */
/*
** Mutex to control access to the memory allocation subsystem.
@@ -99,10 +125,17 @@ static SQLITE_WSD struct Mem5Global {
*/
u8 *aCtrl;
-} mem5 = { 19804167 };
+} mem5 = { 0 };
+/*
+** 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.nAtom]))
/*
@@ -198,7 +231,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 */
@@ -206,12 +245,20 @@ 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( (u32)nByte>mem5.maxRequest ){
mem5.maxRequest = nByte;
}
+ /* Abort if the size is too great */
+ if( nByte > 0x40000000 ){
+ return 0;
+ }
+
/* Round nByte up to the next valid power of two */
for(iFullSz=mem5.nAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
@@ -250,7 +297,7 @@ 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.
@@ -316,26 +363,27 @@ 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.
*/
static void *memsys5Realloc(void *pPrior, int nBytes){
int nOld;
void *p;
- if( pPrior==0 ){
- return memsys5Malloc(nBytes);
- }
+ assert( pPrior!=0 );
if( nBytes<=0 ){
memsys5Free(pPrior);
return 0;
@@ -355,14 +403,20 @@ 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.
*/
static int memsys5Roundup(int n){
int iFullSz;
+ if( n > 0x40000000 ) return 0;
for(iFullSz=mem5.nAtom; iFullSz<n; iFullSz *= 2);
return iFullSz;
}
+/*
+** Return the logarithm base 2 of iValue.
+*/
static int memsys5Log(int iValue){
int iLog;
for(iLog=0; (1<<iLog)<iValue; iLog++);