/* ** 2007 October 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** ** This version of the memory allocation subsystem omits all ** use of malloc(). All dynamically allocatable memory is ** contained in a static array, mem.aPool[]. The size of this ** fixed memory pool is SQLITE_POW2_MEMORY_SIZE bytes. ** ** This version of the memory allocation subsystem is used if ** and only if SQLITE_POW2_MEMORY_SIZE is defined. ** ** $Id: mem5.c,v 1.4 2008/02/19 15:15:16 drh Exp $ */ #include "sqliteInt.h" /* ** This version of the memory allocator is used only when ** SQLITE_POW2_MEMORY_SIZE is defined. */ #ifdef SQLITE_POW2_MEMORY_SIZE /* ** 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 #define POW2_MIN (1<=0 && i=0 && iLogsize=0 ){ mem.aPool[next].u.list.prev = prev; } } /* ** Link the chunk at mem.aPool[i] so that is on the iLogsize ** free list. */ static void memsys5Link(int i, int iLogsize){ int x; assert( sqlite3_mutex_held(mem.mutex) ); assert( i>=0 && i=0 && iLogsize=0 ){ assert( x=POW2_MAX ); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); sqlite3_mutex_enter(mem.mutex); for(i=0; i=0 && i=0 && iLogsize=0 ); while( i>0 ){ if( imem.maxRequest ){ mem.maxRequest = nByte; } /* Simulate a memory allocation fault */ if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ) return 0; /* Round nByte up to the next valid power of two */ if( nByte>POW2_MAX ) return 0; for(iFullSz=POW2_MIN, iLogsize=0; iFullSz=mem.alarmThreshold ){ memsys5Alarm(iFullSz); } /* Make sure mem.aiFreelist[iLogsize] contains at least one free ** block. If not, then split a block of the next larger power of ** two in order to create a new free block of size iLogsize. */ for(iBin=iLogsize; mem.aiFreelist[iBin]<0 && iBin=NSIZE ) return 0; i = memsys5UnlinkFirst(iBin); while( iBin>iLogsize ){ int newSize; iBin--; newSize = 1 << iBin; mem.aCtrl[i+newSize] = CTRL_FREE | iBin; memsys5Link(i+newSize, iBin); } mem.aCtrl[i] = iLogsize; /* Update allocator performance statistics. */ mem.nAlloc++; mem.totalAlloc += iFullSz; mem.totalExcess += iFullSz - nByte; mem.currentCount++; mem.currentOut += iFullSz; if( mem.maxCount=0 && i0 ); assert( mem.currentOut>=0 ); mem.currentCount--; mem.currentOut -= size*POW2_MIN; assert( mem.currentOut>0 || mem.currentCount==0 ); assert( mem.currentCount>0 || mem.currentOut==0 ); mem.aCtrl[i] = CTRL_FREE | iLogsize; while( iLogsize>iLogsize) & 1 ){ iBuddy = i - size; }else{ iBuddy = i + size; } assert( iBuddy>=0 && iBuddy0 ){ memsys5Enter(); p = memsys5Malloc(nBytes); sqlite3_mutex_leave(mem.mutex); } return (void*)p; } /* ** Free memory. */ void sqlite3_free(void *pPrior){ if( pPrior==0 ){ return; } assert( mem.mutex!=0 ); sqlite3_mutex_enter(mem.mutex); memsys5Free(pPrior); sqlite3_mutex_leave(mem.mutex); } /* ** Change the size of an existing memory allocation */ void *sqlite3_realloc(void *pPrior, int nBytes){ int nOld; void *p; if( pPrior==0 ){ return sqlite3_malloc(nBytes); } if( nBytes<=0 ){ sqlite3_free(pPrior); return 0; } assert( mem.mutex!=0 ); nOld = sqlite3MallocSize(pPrior); if( nBytes<=nOld ){ return pPrior; } sqlite3_mutex_enter(mem.mutex); p = memsys5Malloc(nBytes); if( p ){ memcpy(p, pPrior, nOld); memsys5Free(pPrior); } sqlite3_mutex_leave(mem.mutex); return p; } /* ** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ void sqlite3MemdebugDump(const char *zFilename){ #ifdef SQLITE_DEBUG FILE *out; int i, j, n; if( zFilename==0 || zFilename[0]==0 ){ out = stdout; }else{ out = fopen(zFilename, "w"); if( out==0 ){ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", zFilename); return; } } memsys5Enter(); for(i=0; i=0; j = mem.aPool[j].u.list.next, n++){} fprintf(out, "freelist items of size %d: %d\n", POW2_MIN << i, n); } fprintf(out, "mem.nAlloc = %llu\n", mem.nAlloc); fprintf(out, "mem.totalAlloc = %llu\n", mem.totalAlloc); fprintf(out, "mem.totalExcess = %llu\n", mem.totalExcess); fprintf(out, "mem.currentOut = %u\n", mem.currentOut); fprintf(out, "mem.currentCount = %u\n", mem.currentCount); fprintf(out, "mem.maxOut = %u\n", mem.maxOut); fprintf(out, "mem.maxCount = %u\n", mem.maxCount); fprintf(out, "mem.maxRequest = %u\n", mem.maxRequest); sqlite3_mutex_leave(mem.mutex); if( out==stdout ){ fflush(stdout); }else{ fclose(out); } #endif } #endif /* !SQLITE_POW2_MEMORY_SIZE */