Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
mem3.c688 linesDownload Raw Back to src
1/*2** 2007 October 143**4** The author disclaims copyright to this source code.  In place of5** a legal notice, here is a blessing:6**7**    May you do good and not evil.8**    May you find forgiveness for yourself and forgive others.9**    May you share freely, never taking more than you give.10**11*************************************************************************12** This file contains the C functions that implement a memory13** allocation subsystem for use by SQLite. 14**15** This version of the memory allocation subsystem omits all16** use of malloc(). The SQLite user supplies a block of memory17** before calling sqlite3_initialize() from which allocations18** are made and returned by the xMalloc() and xRealloc() 19** implementations. Once sqlite3_initialize() has been called,20** the amount of memory available to SQLite is fixed and cannot21** be changed.22**23** This version of the memory allocation subsystem is included24** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.25*/26#include "sqliteInt.h"27 28/*29** This version of the memory allocator is only built into the library30** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not31** mean that the library will use a memory-pool by default, just that32** it is available. The mempool allocator is activated by calling33** sqlite3_config().34*/35#ifdef SQLITE_ENABLE_MEMSYS336 37/*38** Maximum size (in Mem3Blocks) of a "small" chunk.39*/40#define MX_SMALL 1041 42 43/*44** Number of freelist hash slots45*/46#define N_HASH  6147 48/*49** A memory allocation (also called a "chunk") consists of two or 50** more blocks where each block is 8 bytes.  The first 8 bytes are 51** a header that is not returned to the user.52**53** A chunk is two or more blocks that is either checked out or54** free.  The first block has format u.hdr.  u.hdr.size4x is 4 times the55** size of the allocation in blocks if the allocation is free.56** The u.hdr.size4x&1 bit is true if the chunk is checked out and57** false if the chunk is on the freelist.  The u.hdr.size4x&2 bit58** is true if the previous chunk is checked out and false if the59** previous chunk is free.  The u.hdr.prevSize field is the size of60** the previous chunk in blocks if the previous chunk is on the61** freelist. If the previous chunk is checked out, then62** u.hdr.prevSize can be part of the data for that chunk and should63** not be read or written.64**65** We often identify a chunk by its index in mem3.aPool[].  When66** this is done, the chunk index refers to the second block of67** the chunk.  In this way, the first chunk has an index of 1.68** A chunk index of 0 means "no such chunk" and is the equivalent69** of a NULL pointer.70**71** The second block of free chunks is of the form u.list.  The72** two fields form a double-linked list of chunks of related sizes.73** Pointers to the head of the list are stored in mem3.aiSmall[] 74** for smaller chunks and mem3.aiHash[] for larger chunks.75**76** The second block of a chunk is user data if the chunk is checked 77** out.  If a chunk is checked out, the user data may extend into78** the u.hdr.prevSize value of the following chunk.79*/80typedef struct Mem3Block Mem3Block;81struct Mem3Block {82  union {83    struct {84      u32 prevSize;   /* Size of previous chunk in Mem3Block elements */85      u32 size4x;     /* 4x the size of current chunk in Mem3Block elements */86    } hdr;87    struct {88      u32 next;       /* Index in mem3.aPool[] of next free chunk */89      u32 prev;       /* Index in mem3.aPool[] of previous free chunk */90    } list;91  } u;92};93 94/*95** All of the static variables used by this module are collected96** into a single structure named "mem3".  This is to keep the97** static variables organized and to reduce namespace pollution98** when this module is combined with other in the amalgamation.99*/100static SQLITE_WSD struct Mem3Global {101  /*102  ** Memory available for allocation. nPool is the size of the array103  ** (in Mem3Blocks) pointed to by aPool less 2.104  */105  u32 nPool;106  Mem3Block *aPool;107 108  /*109  ** True if we are evaluating an out-of-memory callback.110  */111  int alarmBusy;112  113  /*114  ** Mutex to control access to the memory allocation subsystem.115  */116  sqlite3_mutex *mutex;117  118  /*119  ** The minimum amount of free space that we have seen.120  */121  u32 mnKeyBlk;122 123  /*124  ** iKeyBlk is the index of the key chunk.  Most new allocations125  ** occur off of this chunk.  szKeyBlk is the size (in Mem3Blocks)126  ** of the current key chunk.  iKeyBlk is 0 if there is no key chunk.127  ** The key chunk is not in either the aiHash[] or aiSmall[].128  */129  u32 iKeyBlk;130  u32 szKeyBlk;131 132  /*133  ** Array of lists of free blocks according to the block size 134  ** for smaller chunks, or a hash on the block size for larger135  ** chunks.136  */137  u32 aiSmall[MX_SMALL-1];   /* For sizes 2 through MX_SMALL, inclusive */138  u32 aiHash[N_HASH];        /* For sizes MX_SMALL+1 and larger */139} mem3 = { 97535575 };140 141#define mem3 GLOBAL(struct Mem3Global, mem3)142 143/*144** Unlink the chunk at mem3.aPool[i] from list it is currently145** on.  *pRoot is the list that i is a member of.146*/147static void memsys3UnlinkFromList(u32 i, u32 *pRoot){148  u32 next = mem3.aPool[i].u.list.next;149  u32 prev = mem3.aPool[i].u.list.prev;150  assert( sqlite3_mutex_held(mem3.mutex) );151  if( prev==0 ){152    *pRoot = next;153  }else{154    mem3.aPool[prev].u.list.next = next;155  }156  if( next ){157    mem3.aPool[next].u.list.prev = prev;158  }159  mem3.aPool[i].u.list.next = 0;160  mem3.aPool[i].u.list.prev = 0;161}162 163/*164** Unlink the chunk at index i from 165** whatever list is currently a member of.166*/167static void memsys3Unlink(u32 i){168  u32 size, hash;169  assert( sqlite3_mutex_held(mem3.mutex) );170  assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );171  assert( i>=1 );172  size = mem3.aPool[i-1].u.hdr.size4x/4;173  assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );174  assert( size>=2 );175  if( size <= MX_SMALL ){176    memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]);177  }else{178    hash = size % N_HASH;179    memsys3UnlinkFromList(i, &mem3.aiHash[hash]);180  }181}182 183/*184** Link the chunk at mem3.aPool[i] so that is on the list rooted185** at *pRoot.186*/187static void memsys3LinkIntoList(u32 i, u32 *pRoot){188  assert( sqlite3_mutex_held(mem3.mutex) );189  mem3.aPool[i].u.list.next = *pRoot;190  mem3.aPool[i].u.list.prev = 0;191  if( *pRoot ){192    mem3.aPool[*pRoot].u.list.prev = i;193  }194  *pRoot = i;195}196 197/*198** Link the chunk at index i into either the appropriate199** small chunk list, or into the large chunk hash table.200*/201static void memsys3Link(u32 i){202  u32 size, hash;203  assert( sqlite3_mutex_held(mem3.mutex) );204  assert( i>=1 );205  assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );206  size = mem3.aPool[i-1].u.hdr.size4x/4;207  assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );208  assert( size>=2 );209  if( size <= MX_SMALL ){210    memsys3LinkIntoList(i, &mem3.aiSmall[size-2]);211  }else{212    hash = size % N_HASH;213    memsys3LinkIntoList(i, &mem3.aiHash[hash]);214  }215}216 217/*218** If the STATIC_MEM mutex is not already held, obtain it now. The mutex219** will already be held (obtained by code in malloc.c) if220** sqlite3GlobalConfig.bMemStat is true.221*/222static void memsys3Enter(void){223  if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){224    mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);225  }226  sqlite3_mutex_enter(mem3.mutex);227}228static void memsys3Leave(void){229  sqlite3_mutex_leave(mem3.mutex);230}231 232/*233** Called when we are unable to satisfy an allocation of nBytes.234*/235static void memsys3OutOfMemory(int nByte){236  if( !mem3.alarmBusy ){237    mem3.alarmBusy = 1;238    assert( sqlite3_mutex_held(mem3.mutex) );239    sqlite3_mutex_leave(mem3.mutex);240    sqlite3_release_memory(nByte);241    sqlite3_mutex_enter(mem3.mutex);242    mem3.alarmBusy = 0;243  }244}245 246 247/*248** Chunk i is a free chunk that has been unlinked.  Adjust its 249** size parameters for check-out and return a pointer to the 250** user portion of the chunk.251*/252static void *memsys3Checkout(u32 i, u32 nBlock){253  u32 x;254  assert( sqlite3_mutex_held(mem3.mutex) );255  assert( i>=1 );256  assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock );257  assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );258  x = mem3.aPool[i-1].u.hdr.size4x;259  mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2);260  mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock;261  mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2;262  return &mem3.aPool[i];263}264 265/*266** Carve a piece off of the end of the mem3.iKeyBlk free chunk.267** Return a pointer to the new allocation.  Or, if the key chunk268** is not large enough, return 0.269*/270static void *memsys3FromKeyBlk(u32 nBlock){271  assert( sqlite3_mutex_held(mem3.mutex) );272  assert( mem3.szKeyBlk>=nBlock );273  if( nBlock>=mem3.szKeyBlk-1 ){274    /* Use the entire key chunk */275    void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk);276    mem3.iKeyBlk = 0;277    mem3.szKeyBlk = 0;278    mem3.mnKeyBlk = 0;279    return p;280  }else{281    /* Split the key block.  Return the tail. */282    u32 newi, x;283    newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock;284    assert( newi > mem3.iKeyBlk+1 );285    mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock;286    mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2;287    mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;288    mem3.szKeyBlk -= nBlock;289    mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk;290    x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;291    mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;292    if( mem3.szKeyBlk < mem3.mnKeyBlk ){293      mem3.mnKeyBlk = mem3.szKeyBlk;294    }295    return (void*)&mem3.aPool[newi];296  }297}298 299/*300** *pRoot is the head of a list of free chunks of the same size301** or same size hash.  In other words, *pRoot is an entry in either302** mem3.aiSmall[] or mem3.aiHash[].  303**304** This routine examines all entries on the given list and tries305** to coalesce each entries with adjacent free chunks.  306**307** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces 308** the current mem3.iKeyBlk with the new larger chunk.  In order for309** this mem3.iKeyBlk replacement to work, the key chunk must be310** linked into the hash tables.  That is not the normal state of311** affairs, of course.  The calling routine must link the key312** chunk before invoking this routine, then must unlink the (possibly313** changed) key chunk once this routine has finished.314*/315static void memsys3Merge(u32 *pRoot){316  u32 iNext, prev, size, i, x;317 318  assert( sqlite3_mutex_held(mem3.mutex) );319  for(i=*pRoot; i>0; i=iNext){320    iNext = mem3.aPool[i].u.list.next;321    size = mem3.aPool[i-1].u.hdr.size4x;322    assert( (size&1)==0 );323    if( (size&2)==0 ){324      memsys3UnlinkFromList(i, pRoot);325      assert( i > mem3.aPool[i-1].u.hdr.prevSize );326      prev = i - mem3.aPool[i-1].u.hdr.prevSize;327      if( prev==iNext ){328        iNext = mem3.aPool[prev].u.list.next;329      }330      memsys3Unlink(prev);331      size = i + size/4 - prev;332      x = mem3.aPool[prev-1].u.hdr.size4x & 2;333      mem3.aPool[prev-1].u.hdr.size4x = size*4 | x;334      mem3.aPool[prev+size-1].u.hdr.prevSize = size;335      memsys3Link(prev);336      i = prev;337    }else{338      size /= 4;339    }340    if( size>mem3.szKeyBlk ){341      mem3.iKeyBlk = i;342      mem3.szKeyBlk = size;343    }344  }345}346 347/*348** Return a block of memory of at least nBytes in size.349** Return NULL if unable.350**351** This function assumes that the necessary mutexes, if any, are352** already held by the caller. Hence "Unsafe".353*/354static void *memsys3MallocUnsafe(int nByte){355  u32 i;356  u32 nBlock;357  u32 toFree;358 359  assert( sqlite3_mutex_held(mem3.mutex) );360  assert( sizeof(Mem3Block)==8 );361  if( nByte<=12 ){362    nBlock = 2;363  }else{364    nBlock = (nByte + 11)/8;365  }366  assert( nBlock>=2 );367 368  /* STEP 1:369  ** Look for an entry of the correct size in either the small370  ** chunk table or in the large chunk hash table.  This is371  ** successful most of the time (about 9 times out of 10).372  */373  if( nBlock <= MX_SMALL ){374    i = mem3.aiSmall[nBlock-2];375    if( i>0 ){376      memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]);377      return memsys3Checkout(i, nBlock);378    }379  }else{380    int hash = nBlock % N_HASH;381    for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){382      if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){383        memsys3UnlinkFromList(i, &mem3.aiHash[hash]);384        return memsys3Checkout(i, nBlock);385      }386    }387  }388 389  /* STEP 2:390  ** Try to satisfy the allocation by carving a piece off of the end391  ** of the key chunk.  This step usually works if step 1 fails.392  */393  if( mem3.szKeyBlk>=nBlock ){394    return memsys3FromKeyBlk(nBlock);395  }396 397 398  /* STEP 3:  399  ** Loop through the entire memory pool.  Coalesce adjacent free400  ** chunks.  Recompute the key chunk as the largest free chunk.401  ** Then try again to satisfy the allocation by carving a piece off402  ** of the end of the key chunk.  This step happens very403  ** rarely (we hope!)404  */405  for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){406    memsys3OutOfMemory(toFree);407    if( mem3.iKeyBlk ){408      memsys3Link(mem3.iKeyBlk);409      mem3.iKeyBlk = 0;410      mem3.szKeyBlk = 0;411    }412    for(i=0; i<N_HASH; i++){413      memsys3Merge(&mem3.aiHash[i]);414    }415    for(i=0; i<MX_SMALL-1; i++){416      memsys3Merge(&mem3.aiSmall[i]);417    }418    if( mem3.szKeyBlk ){419      memsys3Unlink(mem3.iKeyBlk);420      if( mem3.szKeyBlk>=nBlock ){421        return memsys3FromKeyBlk(nBlock);422      }423    }424  }425 426  /* If none of the above worked, then we fail. */427  return 0;428}429 430/*431** Free an outstanding memory allocation.432**433** This function assumes that the necessary mutexes, if any, are434** already held by the caller. Hence "Unsafe".435*/436static void memsys3FreeUnsafe(void *pOld){437  Mem3Block *p = (Mem3Block*)pOld;438  int i;439  u32 size, x;440  assert( sqlite3_mutex_held(mem3.mutex) );441  assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] );442  i = p - mem3.aPool;443  assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 );444  size = mem3.aPool[i-1].u.hdr.size4x/4;445  assert( i+size<=mem3.nPool+1 );446  mem3.aPool[i-1].u.hdr.size4x &= ~1;447  mem3.aPool[i+size-1].u.hdr.prevSize = size;448  mem3.aPool[i+size-1].u.hdr.size4x &= ~2;449  memsys3Link(i);450 451  /* Try to expand the key using the newly freed chunk */452  if( mem3.iKeyBlk ){453    while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){454      size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize;455      mem3.iKeyBlk -= size;456      mem3.szKeyBlk += size;457      memsys3Unlink(mem3.iKeyBlk);458      x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;459      mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;460      mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;461    }462    x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;463    while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){464      memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk);465      mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4;466      mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;467      mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;468    }469  }470}471 472/*473** Return the size of an outstanding allocation, in bytes.  The474** size returned omits the 8-byte header overhead.  This only475** works for chunks that are currently checked out.476*/477static int memsys3Size(void *p){478  Mem3Block *pBlock;479  assert( p!=0 );480  pBlock = (Mem3Block*)p;481  assert( (pBlock[-1].u.hdr.size4x&1)!=0 );482  return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;483}484 485/*486** Round up a request size to the next valid allocation size.487*/488static int memsys3Roundup(int n){489  if( n<=12 ){490    return 12;491  }else{492    return ((n+11)&~7) - 4;493  }494}495 496/*497** Allocate nBytes of memory.498*/499static void *memsys3Malloc(int nBytes){500  sqlite3_int64 *p;501  assert( nBytes>0 );          /* malloc.c filters out 0 byte requests */502  memsys3Enter();503  p = memsys3MallocUnsafe(nBytes);504  memsys3Leave();505  return (void*)p; 506}507 508/*509** Free memory.510*/511static void memsys3Free(void *pPrior){512  assert( pPrior );513  memsys3Enter();514  memsys3FreeUnsafe(pPrior);515  memsys3Leave();516}517 518/*519** Change the size of an existing memory allocation520*/521static void *memsys3Realloc(void *pPrior, int nBytes){522  int nOld;523  void *p;524  if( pPrior==0 ){525    return sqlite3_malloc(nBytes);526  }527  if( nBytes<=0 ){528    sqlite3_free(pPrior);529    return 0;530  }531  nOld = memsys3Size(pPrior);532  if( nBytes<=nOld && nBytes>=nOld-128 ){533    return pPrior;534  }535  memsys3Enter();536  p = memsys3MallocUnsafe(nBytes);537  if( p ){538    if( nOld<nBytes ){539      memcpy(p, pPrior, nOld);540    }else{541      memcpy(p, pPrior, nBytes);542    }543    memsys3FreeUnsafe(pPrior);544  }545  memsys3Leave();546  return p;547}548 549/*550** Initialize this module.551*/552static int memsys3Init(void *NotUsed){553  UNUSED_PARAMETER(NotUsed);554  if( !sqlite3GlobalConfig.pHeap ){555    return SQLITE_ERROR;556  }557 558  /* Store a pointer to the memory block in global structure mem3. */559  assert( sizeof(Mem3Block)==8 );560  mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;561  mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;562 563  /* Initialize the key block. */564  mem3.szKeyBlk = mem3.nPool;565  mem3.mnKeyBlk = mem3.szKeyBlk;566  mem3.iKeyBlk = 1;567  mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2;568  mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;569  mem3.aPool[mem3.nPool].u.hdr.size4x = 1;570 571  return SQLITE_OK;572}573 574/*575** Deinitialize this module.576*/577static void memsys3Shutdown(void *NotUsed){578  UNUSED_PARAMETER(NotUsed);579  mem3.mutex = 0;580  return;581}582 583 584 585/*586** Open the file indicated and write a log of all unfreed memory 587** allocations into that log.588*/589void sqlite3Memsys3Dump(const char *zFilename){590#ifdef SQLITE_DEBUG591  FILE *out;592  u32 i, j;593  u32 size;594  if( zFilename==0 || zFilename[0]==0 ){595    out = stdout;596  }else{597    out = fopen(zFilename, "w");598    if( out==0 ){599      fprintf(stderr, "** Unable to output memory debug output log: %s **\n",600                      zFilename);601      return;602    }603  }604  memsys3Enter();605  fprintf(out, "CHUNKS:\n");606  for(i=1; i<=mem3.nPool; i+=size/4){607    size = mem3.aPool[i-1].u.hdr.size4x;608    if( size/4<=1 ){609      fprintf(out, "%p size error\n", &mem3.aPool[i]);610      assert( 0 );611      break;612    }613    if( (size&1)==0 && mem3.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){614      fprintf(out, "%p tail size does not match\n", &mem3.aPool[i]);615      assert( 0 );616      break;617    }618    if( ((mem3.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){619      fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]);620      assert( 0 );621      break;622    }623    if( size&1 ){624      fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);625    }else{626      fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,627                  i==mem3.iKeyBlk ? " **key**" : "");628    }629  }630  for(i=0; i<MX_SMALL-1; i++){631    if( mem3.aiSmall[i]==0 ) continue;632    fprintf(out, "small(%2d):", i);633    for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){634      fprintf(out, " %p(%d)", &mem3.aPool[j],635              (mem3.aPool[j-1].u.hdr.size4x/4)*8-8);636    }637    fprintf(out, "\n"); 638  }639  for(i=0; i<N_HASH; i++){640    if( mem3.aiHash[i]==0 ) continue;641    fprintf(out, "hash(%2d):", i);642    for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){643      fprintf(out, " %p(%d)", &mem3.aPool[j],644              (mem3.aPool[j-1].u.hdr.size4x/4)*8-8);645    }646    fprintf(out, "\n"); 647  }648  fprintf(out, "key=%d\n", mem3.iKeyBlk);649  fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8);650  fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8);651  sqlite3_mutex_leave(mem3.mutex);652  if( out==stdout ){653    fflush(stdout);654  }else{655    fclose(out);656  }657#else658  UNUSED_PARAMETER(zFilename);659#endif660}661 662/*663** This routine is the only routine in this file with external 664** linkage.665**666** Populate the low-level memory allocation function pointers in667** sqlite3GlobalConfig.m with pointers to the routines in this file. The668** arguments specify the block of memory to manage.669**670** This routine is only called by sqlite3_config(), and therefore671** is not required to be threadsafe (it is not).672*/673const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){674  static const sqlite3_mem_methods mempoolMethods = {675     memsys3Malloc,676     memsys3Free,677     memsys3Realloc,678     memsys3Size,679     memsys3Roundup,680     memsys3Init,681     memsys3Shutdown,682     0683  };684  return &mempoolMethods;685}686 687#endif /* SQLITE_ENABLE_MEMSYS3 */688