diff options
Diffstat (limited to 'src/mem1.c')
| -rw-r--r-- | src/mem1.c | 137 | 
1 files changed, 133 insertions, 4 deletions
| @@ -15,7 +15,31 @@  ** to obtain the memory it needs.  **  ** This file contains implementations of the low-level memory allocation -** routines specified in the sqlite3_mem_methods object. +** routines specified in the sqlite3_mem_methods object.  The content of +** this file is only used if SQLITE_SYSTEM_MALLOC is defined.  The +** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the +** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined.  The +** default configuration is to use memory allocation routines in this +** file. +** +** C-preprocessor macro summary: +** +**    HAVE_MALLOC_USABLE_SIZE     The configure script sets this symbol if +**                                the malloc_usable_size() interface exists +**                                on the target platform.  Or, this symbol +**                                can be set manually, if desired. +**                                If an equivalent interface exists by +**                                a different name, using a separate -D +**                                option to rename it. +** +**    SQLITE_WITHOUT_ZONEMALLOC   Some older macs lack support for the zone +**                                memory allocator.  Set this symbol to enable +**                                building on older macs. +** +**    SQLITE_WITHOUT_MSIZE        Set this symbol to disable the use of +**                                _msize() on windows systems.  This might +**                                be necessary when compiling for Delphi, +**                                for example.  */  #include "sqliteInt.h" @@ -27,6 +51,55 @@  #ifdef SQLITE_SYSTEM_MALLOC  /* +** The MSVCRT has malloc_usable_size() but it is called _msize(). +** The use of _msize() is automatic, but can be disabled by compiling +** with -DSQLITE_WITHOUT_MSIZE +*/ +#if defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE) +# define SQLITE_MALLOCSIZE _msize +#endif + +#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) + +/* +** Use the zone allocator available on apple products unless the +** SQLITE_WITHOUT_ZONEMALLOC symbol is defined. +*/ +#include <sys/sysctl.h> +#include <malloc/malloc.h> +#include <libkern/OSAtomic.h> +static malloc_zone_t* _sqliteZone_; +#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) +#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); +#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y)) +#define SQLITE_MALLOCSIZE(x) \ +        (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x)) + +#else /* if not __APPLE__ */ + +/* +** Use standard C library malloc and free on non-Apple systems.   +** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined. +*/ +#define SQLITE_MALLOC(x)    malloc(x) +#define SQLITE_FREE(x)      free(x) +#define SQLITE_REALLOC(x,y) realloc((x),(y)) + +#if (defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)) \ +      || (defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE)) +# include <malloc.h>    /* Needed for malloc_usable_size on linux */ +#endif +#ifdef HAVE_MALLOC_USABLE_SIZE +# ifndef SQLITE_MALLOCSIZE +#  define SQLITE_MALLOCSIZE(x) malloc_usable_size(x) +# endif +#else +# undef SQLITE_MALLOCSIZE +#endif + +#endif /* __APPLE__ or not __APPLE__ */ + +/*  ** Like malloc(), but remember the size of the allocation  ** so that we can find it later using sqlite3MemSize().  ** @@ -35,10 +108,18 @@  ** routines.  */  static void *sqlite3MemMalloc(int nByte){ +#ifdef SQLITE_MALLOCSIZE +  void *p = SQLITE_MALLOC( nByte ); +  if( p==0 ){ +    testcase( sqlite3GlobalConfig.xLog!=0 ); +    sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); +  } +  return p; +#else    sqlite3_int64 *p;    assert( nByte>0 );    nByte = ROUND8(nByte); -  p = malloc( nByte+8 ); +  p = SQLITE_MALLOC( nByte+8 );    if( p ){      p[0] = nByte;      p++; @@ -47,6 +128,7 @@ static void *sqlite3MemMalloc(int nByte){      sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);    }    return (void *)p; +#endif  }  /* @@ -58,10 +140,14 @@ static void *sqlite3MemMalloc(int nByte){  ** by higher-level routines.  */  static void sqlite3MemFree(void *pPrior){ +#ifdef SQLITE_MALLOCSIZE +  SQLITE_FREE(pPrior); +#else    sqlite3_int64 *p = (sqlite3_int64*)pPrior;    assert( pPrior!=0 );    p--; -  free(p); +  SQLITE_FREE(p); +#endif  }  /* @@ -69,11 +155,15 @@ static void sqlite3MemFree(void *pPrior){  ** or xRealloc().  */  static int sqlite3MemSize(void *pPrior){ +#ifdef SQLITE_MALLOCSIZE +  return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0; +#else    sqlite3_int64 *p;    if( pPrior==0 ) return 0;    p = (sqlite3_int64*)pPrior;    p--;    return (int)p[0]; +#endif  }  /* @@ -87,11 +177,21 @@ static int sqlite3MemSize(void *pPrior){  ** routines and redirected to xFree.  */  static void *sqlite3MemRealloc(void *pPrior, int nByte){ +#ifdef SQLITE_MALLOCSIZE +  void *p = SQLITE_REALLOC(pPrior, nByte); +  if( p==0 ){ +    testcase( sqlite3GlobalConfig.xLog!=0 ); +    sqlite3_log(SQLITE_NOMEM, +      "failed memory resize %u to %u bytes", +      SQLITE_MALLOCSIZE(pPrior), nByte); +  } +  return p; +#else    sqlite3_int64 *p = (sqlite3_int64*)pPrior;    assert( pPrior!=0 && nByte>0 );    assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */    p--; -  p = realloc(p, nByte+8 ); +  p = SQLITE_REALLOC(p, nByte+8 );    if( p ){      p[0] = nByte;      p++; @@ -102,6 +202,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){        sqlite3MemSize(pPrior), nByte);    }    return (void*)p; +#endif  }  /* @@ -115,6 +216,34 @@ static int sqlite3MemRoundup(int n){  ** Initialize this module.  */  static int sqlite3MemInit(void *NotUsed){ +#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) +  int cpuCount; +  size_t len; +  if( _sqliteZone_ ){ +    return SQLITE_OK; +  } +  len = sizeof(cpuCount); +  /* One usually wants to use hw.acctivecpu for MT decisions, but not here */ +  sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0); +  if( cpuCount>1 ){ +    /* defer MT decisions to system malloc */ +    _sqliteZone_ = malloc_default_zone(); +  }else{ +    /* only 1 core, use our own zone to contention over global locks,  +    ** e.g. we have our own dedicated locks */ +    bool success;		 +    malloc_zone_t* newzone = malloc_create_zone(4096, 0); +    malloc_set_zone_name(newzone, "Sqlite_Heap"); +    do{ +      success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,  +                                 (void * volatile *)&_sqliteZone_); +    }while(!_sqliteZone_); +    if( !success ){	 +      /* somebody registered a zone first */ +      malloc_destroy_zone(newzone); +    } +  } +#endif    UNUSED_PARAMETER(NotUsed);    return SQLITE_OK;  } | 
