⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mem5.c

📁 SQLite is a software library that implements a self-contained, serverless, zero-configuration, trans
💻 C
字号:
/*** 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<<SQLITE_POW2_LOGMIN)/*** Log2 of the maximum size of an allocation.*/#ifndef SQLITE_POW2_LOGMAX# define SQLITE_POW2_LOGMAX 18#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.*/typedef struct Mem5Block Mem5Block;struct Mem5Block {  union {    char aData[POW2_MIN];    struct {      int next;       /* Index in mem.aPool[] of next free chunk */      int prev;       /* Index in mem.aPool[] of previous free chunk */    } list;  } u;};/*** Number of blocks of memory available for allocation.*/#define NBLOCK (SQLITE_POW2_MEMORY_SIZE/POW2_MIN)/*** The size in blocks of an POW2_MAX allocation*/#define SZ_MAX (1<<(NSIZE-1))/*** Masks used for mem.aCtrl[] elements.*/#define CTRL_LOGSIZE  0x1f    /* Log2 Size of this block relative to POW2_MIN */#define CTRL_FREE     0x20    /* True if not checked out *//*** 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;  /*  ** Performance statistics  */  u64 nAlloc;         /* Total number of calls to malloc */  u64 totalAlloc;     /* Total of all malloc calls - includes internal frag */  u64 totalExcess;    /* Total internal fragmentation */  u32 currentOut;     /* Current checkout, including internal fragmentation */  u32 currentCount;   /* Current number of distinct checkouts */  u32 maxOut;         /* Maximum instantaneous currentOut */  u32 maxCount;       /* Maximum instantaneous currentCount */  u32 maxRequest;     /* Largest allocation (exclusive of internal frag) */    /*  ** Lists of free blocks of various sizes.  */  int aiFreelist[NSIZE];  /*  ** Space for tracking which blocks are checked out and the size  ** of each block.  One byte per block.  */  u8 aCtrl[NBLOCK];  /*  ** Memory available for allocation  */  Mem5Block aPool[NBLOCK];} mem;/*** Unlink the chunk at mem.aPool[i] from list it is currently** on.  It should be found on mem.aiFreelist[iLogsize].*/static void memsys5Unlink(int i, int iLogsize){  int next, prev;  assert( i>=0 && i<NBLOCK );  assert( iLogsize>=0 && iLogsize<NSIZE );  assert( (mem.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );  assert( sqlite3_mutex_held(mem.mutex) );  next = mem.aPool[i].u.list.next;  prev = mem.aPool[i].u.list.prev;  if( prev<0 ){    mem.aiFreelist[iLogsize] = next;  }else{    mem.aPool[prev].u.list.next = next;  }  if( next>=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<NBLOCK );  assert( iLogsize>=0 && iLogsize<NSIZE );  assert( (mem.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );  mem.aPool[i].u.list.next = x = mem.aiFreelist[iLogsize];  mem.aPool[i].u.list.prev = -1;  if( x>=0 ){    assert( x<NBLOCK );    mem.aPool[x].u.list.prev = i;  }  mem.aiFreelist[iLogsize] = i;}/*** Enter the mutex mem.mutex. Allocate it if it is not already allocated.**** Also:  Initialize the memory allocation subsystem the first time** this routine is called.*/static void memsys5Enter(void){  if( mem.mutex==0 ){    int i;    assert( sizeof(Mem5Block)==POW2_MIN );    assert( (SQLITE_POW2_MEMORY_SIZE % POW2_MAX)==0 );    assert( SQLITE_POW2_MEMORY_SIZE>=POW2_MAX );    mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);    sqlite3_mutex_enter(mem.mutex);    for(i=0; i<NSIZE; i++) mem.aiFreelist[i] = -1;    for(i=0; i<=NBLOCK-SZ_MAX; i += SZ_MAX){      mem.aCtrl[i] = (NSIZE-1) | CTRL_FREE;      memsys5Link(i, NSIZE-1);    }  }else{    sqlite3_mutex_enter(mem.mutex);  }}/*** Return the amount of memory currently checked out.*/sqlite3_int64 sqlite3_memory_used(void){  return mem.currentOut;}/*** 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.*/sqlite3_int64 sqlite3_memory_highwater(int resetFlag){  sqlite3_int64 n;  memsys5Enter();  n = mem.maxOut;  if( resetFlag ){    mem.maxOut = mem.currentOut;  }  sqlite3_mutex_leave(mem.mutex);    return n;}/*** Trigger the alarm */static void memsys5Alarm(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.currentOut;  pArg = mem.alarmArg;  sqlite3_mutex_leave(mem.mutex);  xCallback(pArg, nowUsed, nByte);  sqlite3_mutex_enter(mem.mutex);  mem.alarmBusy = 0;}/*** Change the alarm callback.**** This is a no-op for the static memory allocator.  The purpose** of the memory alarm is to support sqlite3_soft_heap_limit().** But with this memory allocator, the soft_heap_limit is really** a hard limit that is fixed at SQLITE_POW2_MEMORY_SIZE.*/int sqlite3_memory_alarm(  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),  void *pArg,  sqlite3_int64 iThreshold){  memsys5Enter();  mem.alarmCallback = xCallback;  mem.alarmArg = pArg;  mem.alarmThreshold = iThreshold;  sqlite3_mutex_leave(mem.mutex);  return SQLITE_OK;}/*** Return the size of an outstanding allocation, in bytes.  The** size returned omits the 8-byte header overhead.  This only** works for chunks that are currently checked out.*/int sqlite3MallocSize(void *p){  int iSize = 0;  if( p ){    int i = ((Mem5Block*)p) - mem.aPool;    assert( i>=0 && i<NBLOCK );    iSize = 1 << ((mem.aCtrl[i]&CTRL_LOGSIZE) + SQLITE_POW2_LOGMIN);  }  return iSize;}/*** Find the first entry on the freelist iLogsize.  Unlink that** entry and return its index. */static int memsys5UnlinkFirst(int iLogsize){  int i;  int iFirst;  assert( iLogsize>=0 && iLogsize<NSIZE );  i = iFirst = mem.aiFreelist[iLogsize];  assert( iFirst>=0 );  while( i>0 ){    if( i<iFirst ) iFirst = i;    i = mem.aPool[i].u.list.next;  }  memsys5Unlink(iFirst, iLogsize);  return iFirst;}/*** Return a block of memory of at least nBytes in size.** Return NULL if unable.*/static void *memsys5Malloc(int nByte){  int i;           /* Index of a mem.aPool[] slot */  int iBin;        /* Index into mem.aiFreelist[] */  int iFullSz;     /* Size of allocation rounded up to power of 2 */  int iLogsize;    /* Log2 of iFullSz/POW2_MIN */  assert( sqlite3_mutex_held(mem.mutex) );  /* Keep track of the maximum allocation request.  Even unfulfilled  ** requests are counted */  if( nByte>mem.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<nByte; iFullSz *= 2, iLogsize++){}  /* If we will be over the memory alarm threshold after this allocation,  ** then trigger the memory overflow alarm */  if( mem.alarmCallback!=0 && mem.currentOut+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; iBin++){}  if( 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<mem.currentCount ) mem.maxCount = mem.currentCount;  if( mem.maxOut<mem.currentOut ) mem.maxOut = mem.currentOut;  /* Return a pointer to the allocated memory. */  return (void*)&mem.aPool[i];}/*** Free an outstanding memory allocation.*/void memsys5Free(void *pOld){  u32 size, iLogsize;  int i;  i = ((Mem5Block*)pOld) - mem.aPool;  assert( sqlite3_mutex_held(mem.mutex) );  assert( i>=0 && i<NBLOCK );  assert( (mem.aCtrl[i] & CTRL_FREE)==0 );  iLogsize = mem.aCtrl[i] & CTRL_LOGSIZE;  size = 1<<iLogsize;  assert( i+size-1<NBLOCK );  mem.aCtrl[i] |= CTRL_FREE;  mem.aCtrl[i+size-1] |= CTRL_FREE;  assert( mem.currentCount>0 );  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<NSIZE-1 ){    int iBuddy;    if( (i>>iLogsize) & 1 ){      iBuddy = i - size;    }else{      iBuddy = i + size;    }    assert( iBuddy>=0 && iBuddy<NBLOCK );    if( mem.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;    memsys5Unlink(iBuddy, iLogsize);    iLogsize++;    if( iBuddy<i ){      mem.aCtrl[iBuddy] = CTRL_FREE | iLogsize;      mem.aCtrl[i] = 0;      i = iBuddy;    }else{      mem.aCtrl[i] = CTRL_FREE | iLogsize;      mem.aCtrl[iBuddy] = 0;    }    size *= 2;  }  memsys5Link(i, iLogsize);}/*** Allocate nBytes of memory*/void *sqlite3_malloc(int nBytes){  sqlite3_int64 *p = 0;  if( nBytes>0 ){    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<NSIZE; i++){    for(n=0, j=mem.aiFreelist[i]; j>=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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -