/*** 2007 August 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. **** $Id: mem1.cpp 1282 2008-11-13 09:31:33Z LarsPson $*//*** This version of the memory allocator is the default. It is** used when no other memory allocator is specified using compile-time** macros.*/#if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_MEMORY_SIZE) \ && !defined(SQLITE_MMAP_HEAP_SIZE)/*** We will eventually construct multiple memory allocation subsystems** suitable for use in various contexts:**** * Normal multi-threaded builds** * Normal single-threaded builds** * Debugging builds**** This initial version is suitable for use in normal multi-threaded** builds. We envision that alternative versions will be stored in** separate source files. #ifdefs will be used to select the code from** one of the various memN.c source files for use in any given build.*/#include "sqliteInt.h"/*** 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 { /* ** 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_int64 alarmThreshold; void (*alarmCallback)(void*, sqlite3_int64,int); void *alarmArg; int alarmBusy; /* ** Mutex to control access to the memory allocation subsystem. */ sqlite3_mutex *mutex; /* ** Current allocation and high-water mark. */ sqlite3_int64 nowUsed; sqlite3_int64 mxUsed;} mem;/*** Enter the mutex mem.mutex. Allocate it if it is not already allocated.*/static void enterMem(void){ if( mem.mutex==0 ){ mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); } sqlite3_mutex_enter(mem.mutex);}/*** Return the amount of memory currently checked out.*/EXPORT_C sqlite3_int64 sqlite3_memory_used(void){ sqlite3_int64 n; enterMem(); 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.*/EXPORT_C sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ sqlite3_int64 n; enterMem(); n = mem.mxUsed; if( resetFlag ){ mem.mxUsed = mem.nowUsed; } sqlite3_mutex_leave(mem.mutex); return n;}/*** Change the alarm callback*/EXPORT_C int sqlite3_memory_alarm( void(*xCallback)(void *pArg, sqlite3_int64 used,int N), void *pArg, sqlite3_int64 iThreshold){ enterMem(); mem.alarmCallback = xCallback; mem.alarmArg = pArg; mem.alarmThreshold = iThreshold; sqlite3_mutex_leave(mem.mutex); return SQLITE_OK;}/*** Trigger the alarm */static void sqlite3MemsysAlarm(int nByte){ void (*xCallback)(void*,sqlite3_int64,int); sqlite3_int64 nowUsed; void *pArg; if( mem.alarmCallback==0 || mem.alarmBusy ) return; mem.alarmBusy = 1; xCallback = mem.alarmCallback; nowUsed = mem.nowUsed; pArg = mem.alarmArg; sqlite3_mutex_leave(mem.mutex); xCallback(pArg, nowUsed, nByte); sqlite3_mutex_enter(mem.mutex); mem.alarmBusy = 0;}/*** Allocate nBytes of memory*/EXPORT_C void *sqlite3_malloc(int nBytes){ sqlite3_int64 *p = 0; if( nBytes>0 ){ enterMem(); if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){ sqlite3MemsysAlarm(nBytes); } p = (sqlite3_int64*)malloc(nBytes+8); if( p==0 ){ sqlite3MemsysAlarm(nBytes); p = (sqlite3_int64*)malloc(nBytes+8); } if( p ){ p[0] = nBytes; p++; mem.nowUsed += nBytes; if( mem.nowUsed>mem.mxUsed ){ mem.mxUsed = mem.nowUsed; } } sqlite3_mutex_leave(mem.mutex); } return (void*)p; }/*** Free memory.*/EXPORT_C void sqlite3_free(void *pPrior){ sqlite3_int64 *p; int nByte; if( pPrior==0 ){ return; } assert( mem.mutex!=0 ); p = (sqlite3_int64*)pPrior; p--; nByte = (int)*p; sqlite3_mutex_enter(mem.mutex); mem.nowUsed -= nByte; free(p); sqlite3_mutex_leave(mem.mutex); }/*** Change the size of an existing memory allocation*/EXPORT_C void *sqlite3_realloc(void *pPrior, int nBytes){ int nOld; sqlite3_int64 *p; if( pPrior==0 ){ return sqlite3_malloc(nBytes); } if( nBytes<=0 ){ sqlite3_free(pPrior); return 0; } p = (sqlite3_int64*)pPrior; p--; nOld = (int)p[0]; assert( mem.mutex!=0 ); sqlite3_mutex_enter(mem.mutex); if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){ sqlite3MemsysAlarm(nBytes-nOld); } p = (sqlite3_int64*)realloc(p, nBytes+8); if( p==0 ){ sqlite3MemsysAlarm(nBytes); p = (sqlite3_int64*)pPrior; p--; p = (sqlite3_int64*)realloc(p, nBytes+8); } if( p ){ p[0] = nBytes; p++; mem.nowUsed += nBytes-nOld; if( mem.nowUsed>mem.mxUsed ){ mem.mxUsed = mem.nowUsed; } } sqlite3_mutex_leave(mem.mutex); return (void*)p;}#endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */