mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-11 18:50:46 +00:00
update nedmalloc to r1116
git-svn-id: https://svn.eduke32.com/eduke32@1509 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
5ea5f4bc9b
commit
dcd7c3c9fe
4 changed files with 1275 additions and 942 deletions
|
@ -35,7 +35,9 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define REPLACE_SYSTEM_ALLOCATOR
|
#define USE_ALLOCATOR 1
|
||||||
|
#define REPLACE_SYSTEM_ALLOCATOR 1
|
||||||
|
#define USE_MAGIC_HEADERS 1
|
||||||
#include "nedmalloc.h"
|
#include "nedmalloc.h"
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
|
|
|
@ -375,7 +375,18 @@ malloc_getpagesize default: derive from system includes, or 4096.
|
||||||
memory from the system in page-size units. This may be (and
|
memory from the system in page-size units. This may be (and
|
||||||
usually is) a function rather than a constant. This is ignored
|
usually is) a function rather than a constant. This is ignored
|
||||||
if WIN32, where page size is determined using getSystemInfo during
|
if WIN32, where page size is determined using getSystemInfo during
|
||||||
initialization.
|
initialization. This may be several megabytes if ENABLE_LARGE_PAGES
|
||||||
|
is enabled.
|
||||||
|
|
||||||
|
ENABLE_LARGE_PAGES default: NOT defined
|
||||||
|
Causes the system page size to be the value of GetLargePageMinimum()
|
||||||
|
if that function is available (Windows Server 2003/Vista or later).
|
||||||
|
This allows the use of large page entries in the MMU which can
|
||||||
|
significantly improve performance in large working set applications
|
||||||
|
as TLB cache load is reduced by a factor of three. Note that enabling
|
||||||
|
this option is equal to locking the process' memory in current
|
||||||
|
implementations of Windows and requires the SE_LOCK_MEMORY_PRIVILEGE
|
||||||
|
to be held by the process in order to succeed.
|
||||||
|
|
||||||
USE_DEV_RANDOM default: 0 (i.e., not used)
|
USE_DEV_RANDOM default: 0 (i.e., not used)
|
||||||
Causes malloc to use /dev/random to initialize secure magic seed for
|
Causes malloc to use /dev/random to initialize secure magic seed for
|
||||||
|
@ -405,6 +416,7 @@ LACKS_STDLIB_H default: NOT defined unless on WIN32
|
||||||
|
|
||||||
DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
|
DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
|
||||||
system_info.dwAllocationGranularity in WIN32,
|
system_info.dwAllocationGranularity in WIN32,
|
||||||
|
GetLargePageMinimum() if ENABLE_LARGE_PAGES,
|
||||||
otherwise 64K.
|
otherwise 64K.
|
||||||
Also settable using mallopt(M_GRANULARITY, x)
|
Also settable using mallopt(M_GRANULARITY, x)
|
||||||
The unit for allocating and deallocating memory from the system. On
|
The unit for allocating and deallocating memory from the system. On
|
||||||
|
@ -418,6 +430,15 @@ DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
|
||||||
versions of malloc, the equivalent of this option was called
|
versions of malloc, the equivalent of this option was called
|
||||||
"TOP_PAD")
|
"TOP_PAD")
|
||||||
|
|
||||||
|
DEFAULT_GRANULARITY_ALIGNED default: undefined (which means page size)
|
||||||
|
Whether to enforce alignment when allocating and deallocating memory
|
||||||
|
from the system i.e. the base address of all allocations will be
|
||||||
|
aligned to DEFAULT_GRANULARITY if it is set. Note that enabling this carries
|
||||||
|
some overhead as multiple calls must now be made when probing for a valid
|
||||||
|
aligned value, however it does greatly ease the checking for whether
|
||||||
|
a given memory pointer was allocated by this allocator rather than
|
||||||
|
some other.
|
||||||
|
|
||||||
DEFAULT_TRIM_THRESHOLD default: 2MB
|
DEFAULT_TRIM_THRESHOLD default: 2MB
|
||||||
Also settable using mallopt(M_TRIM_THRESHOLD, x)
|
Also settable using mallopt(M_TRIM_THRESHOLD, x)
|
||||||
The maximum amount of unused top-most memory to keep before
|
The maximum amount of unused top-most memory to keep before
|
||||||
|
@ -497,6 +518,7 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
#define HAVE_MMAP 1
|
#define HAVE_MMAP 1
|
||||||
#define HAVE_MORECORE 0
|
#define HAVE_MORECORE 0
|
||||||
#define LACKS_UNISTD_H
|
#define LACKS_UNISTD_H
|
||||||
|
@ -1262,7 +1284,7 @@ int mspace_mallopt(int, int);
|
||||||
#endif /* MSPACES */
|
#endif /* MSPACES */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}; /* end of extern "C" */
|
} /* end of extern "C" */
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1277,10 +1299,8 @@ int mspace_mallopt(int, int);
|
||||||
|
|
||||||
/*------------------------------ internal #includes ---------------------- */
|
/*------------------------------ internal #includes ---------------------- */
|
||||||
|
|
||||||
#ifdef WIN32
|
#if defined(WIN32) && defined(_MSC_VER)
|
||||||
#ifndef __GNUC__
|
|
||||||
#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
|
#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
|
||||||
#endif
|
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
#include <stdio.h> /* for printing in malloc_stats */
|
#include <stdio.h> /* for printing in malloc_stats */
|
||||||
|
@ -1516,6 +1536,29 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
|
||||||
((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
|
((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
|
||||||
((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
|
((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
|
||||||
|
|
||||||
|
/*
|
||||||
|
malloc_params holds global properties, including those that can be
|
||||||
|
dynamically set using mallopt. There is a single instance, mparams,
|
||||||
|
initialized in init_mparams. Note that the non-zeroness of "magic"
|
||||||
|
also serves as an initialization flag.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef unsigned int flag_t; /* The type of various bit flag sets */
|
||||||
|
|
||||||
|
struct malloc_params {
|
||||||
|
volatile size_t magic;
|
||||||
|
size_t page_size;
|
||||||
|
size_t granularity;
|
||||||
|
size_t mmap_threshold;
|
||||||
|
size_t trim_threshold;
|
||||||
|
flag_t default_mflags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct malloc_params mparams;
|
||||||
|
|
||||||
|
/* Ensure mparams initialized */
|
||||||
|
#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
|
||||||
|
|
||||||
/* -------------------------- MMAP preliminaries ------------------------- */
|
/* -------------------------- MMAP preliminaries ------------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1532,14 +1575,41 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
|
||||||
#if HAVE_MMAP
|
#if HAVE_MMAP
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
|
|
||||||
#define MMAP_PROT (PROT_READ|PROT_WRITE)
|
|
||||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
#endif /* MAP_ANON */
|
#endif /* MAP_ANON */
|
||||||
|
#ifdef DEFAULT_GRANULARITY_ALIGNED
|
||||||
|
#define MMAP_IMPL mmap_aligned
|
||||||
|
static void* lastAlignedmmap; /* Used as a hint */
|
||||||
|
static void* mmap_aligned(void *start, size_t length, int prot, int flags, int fd, off_t offset) {
|
||||||
|
void* baseaddress = 0;
|
||||||
|
void* ptr = 0;
|
||||||
|
if(!start) {
|
||||||
|
baseaddress = lastAlignedmmap;
|
||||||
|
for(;;) {
|
||||||
|
if(baseaddress) flags|=MAP_FIXED;
|
||||||
|
ptr = mmap(baseaddress, length, prot, flags, fd, offset);
|
||||||
|
if(!ptr)
|
||||||
|
baseaddress = (void*)((size_t)baseaddress + mparams.granularity);
|
||||||
|
else if((size_t)ptr & (mparams.granularity - SIZE_T_ONE)) {
|
||||||
|
munmap(ptr, length);
|
||||||
|
baseaddress = (void*)(((size_t)ptr + mparams.granularity) & ~(mparams.granularity - SIZE_T_ONE));
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else ptr = mmap(start, length, prot, flags, fd, offset);
|
||||||
|
if(ptr) lastAlignedmmap = (void*)((size_t) ptr + mparams.granularity);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define MMAP_IMPL mmap
|
||||||
|
#endif /* DEFAULT_GRANULARITY_ALIGNED */
|
||||||
|
#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
|
||||||
|
#define MMAP_PROT (PROT_READ|PROT_WRITE)
|
||||||
#ifdef MAP_ANONYMOUS
|
#ifdef MAP_ANONYMOUS
|
||||||
#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
|
#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
|
||||||
#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
|
#define MMAP_DEFAULT(s) MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
|
||||||
#else /* MAP_ANONYMOUS */
|
#else /* MAP_ANONYMOUS */
|
||||||
/*
|
/*
|
||||||
Nearly all versions of mmap support MAP_ANONYMOUS, so the following
|
Nearly all versions of mmap support MAP_ANONYMOUS, so the following
|
||||||
|
@ -1549,8 +1619,8 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
|
||||||
static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
|
static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
|
||||||
#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
|
#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
|
||||||
(dev_zero_fd = open("/dev/zero", O_RDWR), \
|
(dev_zero_fd = open("/dev/zero", O_RDWR), \
|
||||||
mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
|
MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
|
||||||
mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
|
MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
|
||||||
#endif /* MAP_ANONYMOUS */
|
#endif /* MAP_ANONYMOUS */
|
||||||
|
|
||||||
#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
|
#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
|
||||||
|
@ -1558,8 +1628,51 @@ static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
|
||||||
#else /* WIN32 */
|
#else /* WIN32 */
|
||||||
|
|
||||||
/* Win32 MMAP via VirtualAlloc */
|
/* Win32 MMAP via VirtualAlloc */
|
||||||
|
#ifdef DEFAULT_GRANULARITY_ALIGNED
|
||||||
|
static void* lastWin32mmap; /* Used as a hint */
|
||||||
|
#endif /* DEFAULT_GRANULARITY_ALIGNED */
|
||||||
|
#ifdef ENABLE_LARGE_PAGES
|
||||||
|
static int largepagesavailable = 1;
|
||||||
|
#endif /* ENABLE_LARGE_PAGES */
|
||||||
static FORCEINLINE void* win32mmap(size_t size) {
|
static FORCEINLINE void* win32mmap(size_t size) {
|
||||||
void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
void* baseaddress = 0;
|
||||||
|
void* ptr = 0;
|
||||||
|
#ifdef ENABLE_LARGE_PAGES
|
||||||
|
/* Note that large pages are *always* allocated on a large page boundary.
|
||||||
|
If however granularity is small then don't waste a kernel call if size
|
||||||
|
isn't around the size of a large page */
|
||||||
|
if(largepagesavailable && size >= 1*1024*1024) {
|
||||||
|
ptr = VirtualAlloc(baseaddress, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||||
|
if(!ptr && ERROR_PRIVILEGE_NOT_HELD==GetLastError()) largepagesavailable=0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(!ptr) {
|
||||||
|
#ifdef DEFAULT_GRANULARITY_ALIGNED
|
||||||
|
/* We try to avoid overhead by speculatively reserving at aligned
|
||||||
|
addresses until we succeed */
|
||||||
|
baseaddress = lastWin32mmap;
|
||||||
|
for(;;) {
|
||||||
|
void* reserveaddr = VirtualAlloc(baseaddress, size, MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
if(!reserveaddr)
|
||||||
|
baseaddress = (void*)((size_t)baseaddress + mparams.granularity);
|
||||||
|
else if((size_t)reserveaddr & (mparams.granularity - SIZE_T_ONE)) {
|
||||||
|
VirtualFree(reserveaddr, 0, MEM_RELEASE);
|
||||||
|
baseaddress = (void*)(((size_t)reserveaddr + mparams.granularity) & ~(mparams.granularity - SIZE_T_ONE));
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(!ptr) ptr = VirtualAlloc(baseaddress, size, baseaddress ? MEM_COMMIT : MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
#if DEBUG
|
||||||
|
if(lastWin32mmap && ptr!=lastWin32mmap) printf("Non-contiguous VirtualAlloc between %p and %p\n", ptr, lastWin32mmap);
|
||||||
|
#endif
|
||||||
|
#ifdef DEFAULT_GRANULARITY_ALIGNED
|
||||||
|
if(ptr) lastWin32mmap = (void*)((size_t) ptr + mparams.granularity);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
printf("VirtualAlloc returns %p size %u\n", ptr, size);
|
||||||
|
#endif
|
||||||
return (ptr != 0)? ptr: MFAIL;
|
return (ptr != 0)? ptr: MFAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1823,15 +1936,14 @@ static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) {
|
||||||
int spins = 0;
|
int spins = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (sl->l != 0) {
|
if (sl->l != 0) {
|
||||||
if (sl->threadid == (signed)CURRENT_THREAD) {
|
if (sl->threadid == CURRENT_THREAD) {
|
||||||
++sl->c;
|
++sl->c;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!interlockedexchange(&sl->l, 1)) {
|
if (!interlockedexchange(&sl->l, 1)) {
|
||||||
assert(!sl->1855
|
assert(!sl->threadid);
|
||||||
);
|
|
||||||
sl->threadid = CURRENT_THREAD;
|
sl->threadid = CURRENT_THREAD;
|
||||||
sl->c = 1;
|
sl->c = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1853,7 +1965,7 @@ static FORCEINLINE void win32_release_lock (MLOCK_T *sl) {
|
||||||
|
|
||||||
static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
|
static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
|
||||||
if (sl->l != 0) {
|
if (sl->l != 0) {
|
||||||
if (sl->threadid == (signed)CURRENT_THREAD) {
|
if (sl->threadid == CURRENT_THREAD) {
|
||||||
++sl->c;
|
++sl->c;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2120,7 +2232,6 @@ typedef struct malloc_chunk* mchunkptr;
|
||||||
typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
|
typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
|
||||||
typedef unsigned int bindex_t; /* Described below */
|
typedef unsigned int bindex_t; /* Described below */
|
||||||
typedef unsigned int binmap_t; /* Described below */
|
typedef unsigned int binmap_t; /* Described below */
|
||||||
typedef unsigned int flag_t; /* The type of various bit flag sets */
|
|
||||||
|
|
||||||
/* ------------------- Chunks sizes and alignments ----------------------- */
|
/* ------------------- Chunks sizes and alignments ----------------------- */
|
||||||
|
|
||||||
|
@ -2513,10 +2624,10 @@ struct malloc_state {
|
||||||
size_t footprint;
|
size_t footprint;
|
||||||
size_t max_footprint;
|
size_t max_footprint;
|
||||||
flag_t mflags;
|
flag_t mflags;
|
||||||
|
msegment seg;
|
||||||
#if USE_LOCKS
|
#if USE_LOCKS
|
||||||
MLOCK_T mutex; /* locate lock among fields that rarely change */
|
MLOCK_T mutex; /* locate lock among fields that rarely change */
|
||||||
#endif /* USE_LOCKS */
|
#endif /* USE_LOCKS */
|
||||||
msegment seg;
|
|
||||||
void* extp; /* Unused but available for extensions */
|
void* extp; /* Unused but available for extensions */
|
||||||
size_t exts;
|
size_t exts;
|
||||||
};
|
};
|
||||||
|
@ -2525,27 +2636,6 @@ typedef struct malloc_state* mstate;
|
||||||
|
|
||||||
/* ------------- Global malloc_state and malloc_params ------------------- */
|
/* ------------- Global malloc_state and malloc_params ------------------- */
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_params holds global properties, including those that can be
|
|
||||||
dynamically set using mallopt. There is a single instance, mparams,
|
|
||||||
initialized in init_mparams. Note that the non-zeroness of "magic"
|
|
||||||
also serves as an initialization flag.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct malloc_params {
|
|
||||||
volatile size_t magic;
|
|
||||||
size_t page_size;
|
|
||||||
size_t granularity;
|
|
||||||
size_t mmap_threshold;
|
|
||||||
size_t trim_threshold;
|
|
||||||
flag_t default_mflags;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct malloc_params mparams;
|
|
||||||
|
|
||||||
/* Ensure mparams initialized */
|
|
||||||
#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
|
|
||||||
|
|
||||||
#if !ONLY_MSPACES
|
#if !ONLY_MSPACES
|
||||||
|
|
||||||
/* The global malloc_state used for all non-"mspace" calls */
|
/* The global malloc_state used for all non-"mspace" calls */
|
||||||
|
@ -2734,7 +2824,7 @@ static size_t traverse_and_check(mstate m);
|
||||||
/* ---------------------------- Indexing Bins ---------------------------- */
|
/* ---------------------------- Indexing Bins ---------------------------- */
|
||||||
|
|
||||||
#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
|
#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
|
||||||
#define small_index(s) ((s) >> SMALLBIN_SHIFT)
|
#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT)
|
||||||
#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
|
#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
|
||||||
#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
|
#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
|
||||||
|
|
||||||
|
@ -2782,7 +2872,7 @@ static size_t traverse_and_check(mstate m);
|
||||||
I = NTREEBINS-1;\
|
I = NTREEBINS-1;\
|
||||||
else {\
|
else {\
|
||||||
unsigned int K;\
|
unsigned int K;\
|
||||||
_BitScanReverse((DWORD *) &K, X);\
|
_BitScanReverse((DWORD *) &K, (DWORD) X);\
|
||||||
I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
|
I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
|
@ -3003,6 +3093,10 @@ static size_t traverse_and_check(mstate m);
|
||||||
|
|
||||||
/* ---------------------------- setting mparams -------------------------- */
|
/* ---------------------------- setting mparams -------------------------- */
|
||||||
|
|
||||||
|
#ifdef ENABLE_LARGE_PAGES
|
||||||
|
typedef size_t (WINAPI *GetLargePageMinimum_t)(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Initialize mparams */
|
/* Initialize mparams */
|
||||||
static int init_mparams(void) {
|
static int init_mparams(void) {
|
||||||
#ifdef NEED_GLOBAL_LOCK_INIT
|
#ifdef NEED_GLOBAL_LOCK_INIT
|
||||||
|
@ -3026,6 +3120,20 @@ static int init_mparams(void) {
|
||||||
psize = system_info.dwPageSize;
|
psize = system_info.dwPageSize;
|
||||||
gsize = ((DEFAULT_GRANULARITY != 0)?
|
gsize = ((DEFAULT_GRANULARITY != 0)?
|
||||||
DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
|
DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
|
||||||
|
#ifdef ENABLE_LARGE_PAGES
|
||||||
|
{
|
||||||
|
GetLargePageMinimum_t GetLargePageMinimum_ = (GetLargePageMinimum_t) GetProcAddress(GetModuleHandle(__T("kernel32.dll")), "GetLargePageMinimum");
|
||||||
|
if(GetLargePageMinimum_) {
|
||||||
|
size_t largepagesize = GetLargePageMinimum_();
|
||||||
|
if(largepagesize) {
|
||||||
|
psize = largepagesize;
|
||||||
|
gsize = ((DEFAULT_GRANULARITY != 0)?
|
||||||
|
DEFAULT_GRANULARITY : largepagesize);
|
||||||
|
if(gsize < largepagesize) gsize = largepagesize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
|
@ -5465,6 +5573,7 @@ int mspace_mallopt(int param_number, int value) {
|
||||||
|
|
||||||
#endif /* MSPACES */
|
#endif /* MSPACES */
|
||||||
|
|
||||||
|
|
||||||
/* -------------------- Alternative MORECORE functions ------------------- */
|
/* -------------------- Alternative MORECORE functions ------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5753,4 +5862,3 @@ History:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* nedalloc, an alternative malloc implementation for multiple threads without
|
/* nedalloc, an alternative malloc implementation for multiple threads without
|
||||||
lock contention based on dlmalloc v2.8.3. (C) 2005 Niall Douglas
|
lock contention based on dlmalloc v2.8.3. (C) 2005-2009 Niall Douglas
|
||||||
|
|
||||||
Boost Software License - Version 1.0 - August 17th, 2003
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
@ -29,8 +29,6 @@ DEALINGS IN THE SOFTWARE.
|
||||||
#ifndef NEDMALLOC_H
|
#ifndef NEDMALLOC_H
|
||||||
#define NEDMALLOC_H
|
#define NEDMALLOC_H
|
||||||
|
|
||||||
#define THREADCACHEMAX 65536
|
|
||||||
#define THREADCACHEMAXFREESPACE (1024*1024*4)
|
|
||||||
|
|
||||||
/* See malloc.c.h for what each function does.
|
/* See malloc.c.h for what each function does.
|
||||||
|
|
||||||
|
@ -40,19 +38,34 @@ free etc. instead of nedmalloc, nedfree etc. You may or may not want this.
|
||||||
NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc
|
NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc
|
||||||
namespace when in C++ (uses the global namespace instead).
|
namespace when in C++ (uses the global namespace instead).
|
||||||
|
|
||||||
EXTSPEC can be defined to be __declspec(dllexport) or
|
NEDMALLOCEXTSPEC can be defined to be __declspec(dllexport) or
|
||||||
__attribute__ ((visibility("default"))) or whatever you like. It defaults
|
__attribute__ ((visibility("default"))) or whatever you like. It defaults
|
||||||
to extern.
|
to extern unless NEDMALLOC_DLL_EXPORTS is set as it would be when building
|
||||||
|
nedmalloc.dll.
|
||||||
|
|
||||||
USE_LOCKS can be 2 if you want to define your own MLOCK_T, INITIAL_LOCK,
|
USE_LOCKS can be 2 if you want to define your own MLOCK_T, INITIAL_LOCK,
|
||||||
ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
|
ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
|
||||||
|
|
||||||
|
USE_MAGIC_HEADERS causes nedalloc to allocate an extra three sizeof(size_t)
|
||||||
|
to each block. nedpfree() and nedprealloc() can then automagically know when
|
||||||
|
to free a system allocated block. Enabling this typically adds 20-50% to
|
||||||
|
application memory usage.
|
||||||
|
|
||||||
|
USE_ALLOCATOR can be one of these settings:
|
||||||
|
0: System allocator (nedmalloc now simply acts as a threadcache).
|
||||||
|
WARNING: Intended for DEBUG USE ONLY - not all functions work correctly.
|
||||||
|
1: dlmalloc
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
#ifndef EXTSPEC
|
#ifndef NEDMALLOCEXTSPEC
|
||||||
#define EXTSPEC extern
|
#ifdef NEDMALLOC_DLL_EXPORTS
|
||||||
|
#define NEDMALLOCEXTSPEC extern __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define NEDMALLOCEXTSPEC extern
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER>=1400
|
#if defined(_MSC_VER) && _MSC_VER>=1400
|
||||||
|
@ -65,7 +78,23 @@ ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
|
||||||
#define NEDMALLOCPTRATTR
|
#define NEDMALLOCPTRATTR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_MAGIC_HEADERS
|
||||||
|
#define USE_MAGIC_HEADERS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_ALLOCATOR
|
||||||
|
#define USE_ALLOCATOR 1 /* dlmalloc */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !USE_ALLOCATOR && !USE_MAGIC_HEADERS
|
||||||
|
#error If you are using the system allocator then you MUST use magic headers
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef REPLACE_SYSTEM_ALLOCATOR
|
#ifdef REPLACE_SYSTEM_ALLOCATOR
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
#error Cannot combine using the system allocator with replacing the system allocator
|
||||||
|
#endif
|
||||||
|
#ifndef WIN32 /* We have a dedidicated patcher for Windows */
|
||||||
#define nedmalloc malloc
|
#define nedmalloc malloc
|
||||||
#define nedcalloc calloc
|
#define nedcalloc calloc
|
||||||
#define nedrealloc realloc
|
#define nedrealloc realloc
|
||||||
|
@ -82,12 +111,8 @@ ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
|
||||||
#define nedblksize _msize
|
#define nedblksize _msize
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#ifndef UNREFERENCED_PARAMETER
|
|
||||||
#define UNREFERENCED_PARAMETER(x) x=x
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NO_MALLINFO
|
#ifndef NO_MALLINFO
|
||||||
#define NO_MALLINFO 0
|
#define NO_MALLINFO 0
|
||||||
|
@ -117,33 +142,36 @@ extern "C" {
|
||||||
/* These are the global functions */
|
/* These are the global functions */
|
||||||
|
|
||||||
/* Gets the usable size of an allocated block. Note this will always be bigger than what was
|
/* Gets the usable size of an allocated block. Note this will always be bigger than what was
|
||||||
asked for due to rounding etc.
|
asked for due to rounding etc. Tries to return zero if this is not a nedmalloc block (though
|
||||||
|
one could see a segfault up to 6.25% of the time). On Win32 SEH is used to guarantee that a
|
||||||
|
segfault never happens.
|
||||||
*/
|
*/
|
||||||
EXTSPEC size_t nedblksize(void *mem) THROWSPEC;
|
NEDMALLOCEXTSPEC size_t nedblksize(void *mem) THROWSPEC;
|
||||||
|
|
||||||
EXTSPEC void nedsetvalue(void *v) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedsetvalue(void *v) THROWSPEC;
|
||||||
|
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
|
||||||
EXTSPEC void nedfree(void *mem) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedfree(void *mem) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
|
||||||
#if !NO_MALLINFO
|
#if !NO_MALLINFO
|
||||||
EXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC;
|
NEDMALLOCEXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC;
|
||||||
#endif
|
#endif
|
||||||
EXTSPEC int nedmallopt(int parno, int value) THROWSPEC;
|
NEDMALLOCEXTSPEC int nedmallopt(int parno, int value) THROWSPEC;
|
||||||
EXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC;
|
NEDMALLOCEXTSPEC void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC;
|
||||||
EXTSPEC void nedmalloc_stats(void) THROWSPEC;
|
NEDMALLOCEXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC;
|
||||||
EXTSPEC size_t nedmalloc_footprint(void) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedmalloc_stats(void) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
|
NEDMALLOCEXTSPEC size_t nedmalloc_footprint(void) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
|
||||||
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
|
||||||
|
|
||||||
/* Destroys the system memory pool used by the functions above.
|
/* Destroys the system memory pool used by the functions above.
|
||||||
Useful for when you have nedmalloc in a DLL you're about to unload.
|
Useful for when you have nedmalloc in a DLL you're about to unload.
|
||||||
If you call ANY nedmalloc functions after calling this you will
|
If you call ANY nedmalloc functions after calling this you will
|
||||||
get a fatal exception!
|
get a fatal exception!
|
||||||
*/
|
*/
|
||||||
EXTSPEC void neddestroysyspool(void) THROWSPEC;
|
NEDMALLOCEXTSPEC void neddestroysyspool() THROWSPEC;
|
||||||
|
|
||||||
/* These are the pool functions */
|
/* These are the pool functions */
|
||||||
struct nedpool_t;
|
struct nedpool_t;
|
||||||
|
@ -156,52 +184,50 @@ will *normally* be accessing the pool concurrently. Setting this to zero means i
|
||||||
extends on demand, but be careful of this as it can rapidly consume system resources
|
extends on demand, but be careful of this as it can rapidly consume system resources
|
||||||
where bursts of concurrent threads use a pool at once.
|
where bursts of concurrent threads use a pool at once.
|
||||||
*/
|
*/
|
||||||
EXTSPEC NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC;
|
||||||
|
|
||||||
/* Destroys a memory pool previously created by nedcreatepool().
|
/* Destroys a memory pool previously created by nedcreatepool().
|
||||||
*/
|
*/
|
||||||
EXTSPEC void neddestroypool(nedpool *p) THROWSPEC;
|
NEDMALLOCEXTSPEC void neddestroypool(nedpool *p) THROWSPEC;
|
||||||
|
|
||||||
/* Sets a value to be associated with a pool. You can retrieve this value by passing
|
/* Sets a value to be associated with a pool. You can retrieve this value by passing
|
||||||
any memory block allocated from that pool.
|
any memory block allocated from that pool.
|
||||||
*/
|
*/
|
||||||
EXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC;
|
||||||
/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown.
|
/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown.
|
||||||
Optionally can also retrieve pool.
|
Optionally can also retrieve pool.
|
||||||
*/
|
*/
|
||||||
EXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC;
|
NEDMALLOCEXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC;
|
||||||
|
|
||||||
/* Trims the thread cache for the calling thread, returning any existing cache
|
/* Trims the thread cache for the calling thread, returning any existing cache
|
||||||
data to the central pool. Remember to ALWAYS call with zero if you used the
|
data to the central pool. Remember to ALWAYS call with zero if you used the
|
||||||
system pool. Setting disable to non-zero replicates neddisablethreadcache().
|
system pool. Setting disable to non-zero replicates neddisablethreadcache().
|
||||||
*/
|
*/
|
||||||
EXTSPEC void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC;
|
||||||
|
|
||||||
/* Disables the thread cache for the calling thread, returning any existing cache
|
/* Disables the thread cache for the calling thread, returning any existing cache
|
||||||
data to the central pool. Remember to ALWAYS call with zero if you used the
|
data to the central pool. Remember to ALWAYS call with zero if you used the
|
||||||
system pool.
|
system pool.
|
||||||
*/
|
*/
|
||||||
EXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
|
NEDMALLOCEXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
|
||||||
|
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
|
||||||
EXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
|
||||||
#if !NO_MALLINFO
|
#if !NO_MALLINFO
|
||||||
EXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC;
|
NEDMALLOCEXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC;
|
||||||
#endif
|
#endif
|
||||||
EXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
|
NEDMALLOCEXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
|
||||||
EXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
|
NEDMALLOCEXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
|
||||||
EXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
|
NEDMALLOCEXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
|
||||||
EXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
|
NEDMALLOCEXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
|
||||||
EXTSPEC NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
|
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef EXTSPEC
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Alternative malloc implementation for multiple threads without
|
/* Alternative malloc implementation for multiple threads without
|
||||||
lock contention based on dlmalloc. (C) 2005-2006 Niall Douglas
|
lock contention based on dlmalloc. (C) 2005-2009 Niall Douglas
|
||||||
|
|
||||||
Boost Software License - Version 1.0 - August 17th, 2003
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
@ -36,14 +36,20 @@ DEALINGS IN THE SOFTWARE.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*#define FULLSANITYCHECKS*/
|
/*#define FULLSANITYCHECKS*/
|
||||||
|
#define USE_ALLOCATOR 1
|
||||||
|
#define REPLACE_SYSTEM_ALLOCATOR 1
|
||||||
|
#define USE_MAGIC_HEADERS 1
|
||||||
|
|
||||||
#include "nedmalloc.h"
|
#include "nedmalloc.h"
|
||||||
#ifdef _WIN32
|
#ifdef WIN32
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
#define MSPACES 1
|
#define MSPACES 1
|
||||||
#define ONLY_MSPACES 1
|
#define ONLY_MSPACES 1
|
||||||
|
#endif
|
||||||
|
#define USE_DL_PREFIX 1
|
||||||
#ifndef USE_LOCKS
|
#ifndef USE_LOCKS
|
||||||
#define USE_LOCKS 1
|
#define USE_LOCKS 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,6 +71,9 @@ DEALINGS IN THE SOFTWARE.
|
||||||
/* The default of 64Kb means we spend too much time kernel-side */
|
/* The default of 64Kb means we spend too much time kernel-side */
|
||||||
#ifndef DEFAULT_GRANULARITY
|
#ifndef DEFAULT_GRANULARITY
|
||||||
#define DEFAULT_GRANULARITY (1*1024*1024)
|
#define DEFAULT_GRANULARITY (1*1024*1024)
|
||||||
|
#if DEBUG
|
||||||
|
#define DEFAULT_GRANULARITY_ALIGNED
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
/*#define USE_SPIN_LOCKS 0*/
|
/*#define USE_SPIN_LOCKS 0*/
|
||||||
|
|
||||||
|
@ -88,30 +97,18 @@ DEALINGS IN THE SOFTWARE.
|
||||||
#endif
|
#endif
|
||||||
/* The maximum size to be allocated from the thread cache */
|
/* The maximum size to be allocated from the thread cache */
|
||||||
#ifndef THREADCACHEMAX
|
#ifndef THREADCACHEMAX
|
||||||
#define THREADCACHEMAX 8192
|
#define THREADCACHEMAX 65536
|
||||||
#endif
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */
|
/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */
|
||||||
#if THREADCACHEMAX == 8192
|
|
||||||
#define THREADCACHEMAXBINS ((13-4)*2)
|
|
||||||
#elif THREADCACHEMAX == 65536
|
|
||||||
#define THREADCACHEMAXBINS ((16-4)*2)
|
#define THREADCACHEMAXBINS ((16-4)*2)
|
||||||
#else
|
#else
|
||||||
#error undefined size
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
|
/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
|
||||||
#if THREADCACHEMAX == 8192
|
|
||||||
#define THREADCACHEMAXBINS (13-4)
|
|
||||||
#elif THREADCACHEMAX == 65536
|
|
||||||
#define THREADCACHEMAXBINS (16-4)
|
#define THREADCACHEMAXBINS (16-4)
|
||||||
#else
|
|
||||||
#error undefined size
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
/* Point at which the free space in a thread cache is garbage collected */
|
/* Point at which the free space in a thread cache is garbage collected */
|
||||||
#ifndef THREADCACHEMAXFREESPACE
|
#ifndef THREADCACHEMAXFREESPACE
|
||||||
#define THREADCACHEMAXFREESPACE (512*1024)
|
#define THREADCACHEMAXFREESPACE (512*1024*8)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,41 +136,190 @@ static LPVOID ChkedTlsGetValue(DWORD idx)
|
||||||
#define TLSSET(k, a) pthread_setspecific(k, a)
|
#define TLSSET(k, a) pthread_setspecific(k, a)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Only enable if testing with valgrind. Causes misoperation */
|
|
||||||
#define mspace_malloc(p, s) malloc(s)
|
|
||||||
#define mspace_realloc(p, m, s) realloc(m, s)
|
|
||||||
#define mspace_calloc(p, n, s) calloc(n, s)
|
|
||||||
#define mspace_free(p, m) free(m)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
#if !defined(NO_NED_NAMESPACE)
|
#if !defined(NO_NED_NAMESPACE)
|
||||||
namespace nedalloc
|
namespace nedalloc {
|
||||||
{
|
|
||||||
#else
|
#else
|
||||||
extern "C"
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void *unsupported_operation(const char *opname) THROWSPEC
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "nedmalloc: The operation %s is not supported under this build configuration\n", opname);
|
||||||
|
abort();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static size_t mspacecounter=(size_t) 0xdeadbeef;
|
||||||
|
|
||||||
|
static FORCEINLINE void *CallMalloc(void *mspace, size_t size, size_t alignment) THROWSPEC
|
||||||
|
{
|
||||||
|
void *ret=0;
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
size_t *_ret=0;
|
||||||
|
size+=alignment+3*sizeof(size_t);
|
||||||
#endif
|
#endif
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
ret=malloc(size);
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
|
ret=mspace_malloc((mstate) mspace, size);
|
||||||
#endif
|
#endif
|
||||||
|
if(!ret) return 0;
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
_ret=(size_t *) ret;
|
||||||
|
ret=(void *)(_ret+3);
|
||||||
|
if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1));
|
||||||
|
for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *)"NEDMALOC";
|
||||||
|
_ret[0]=(size_t) mspace;
|
||||||
|
_ret[1]=size;
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE void *CallCalloc(void *mspace, size_t no, size_t size, size_t alignment) THROWSPEC
|
||||||
|
{
|
||||||
|
void *ret=0;
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
size_t *_ret=0;
|
||||||
|
size+=alignment+3*sizeof(size_t);
|
||||||
|
#endif
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
ret=calloc(no, size);
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
|
ret=mspace_calloc((mstate) mspace, no, size);
|
||||||
|
#endif
|
||||||
|
if(!ret) return 0;
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
_ret=(size_t *) ret;
|
||||||
|
ret=(void *)(_ret+3);
|
||||||
|
if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1));
|
||||||
|
for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC";
|
||||||
|
_ret[0]=(size_t) mspace;
|
||||||
|
_ret[1]=size;
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE void *CallRealloc(void *mspace, void *mem, size_t size) THROWSPEC
|
||||||
|
{
|
||||||
|
void *ret=0;
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
mstate oldmspace=0;
|
||||||
|
size_t *_ret=0, *_mem=(size_t *) mem-3, oldsize=0;
|
||||||
|
if(_mem[0]!=*(size_t *) "NEDMALOC")
|
||||||
|
{ /* Transfer */
|
||||||
|
if((ret=CallMalloc(mspace, size, 0)))
|
||||||
|
{ /* It's probably safe to copy size bytes from mem - can't do much different */
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printf("*** nedmalloc frees system allocated block %p\n", mem);
|
||||||
|
#endif
|
||||||
|
memcpy(ret, mem, size);
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
size+=3*sizeof(size_t);
|
||||||
|
oldmspace=(mstate) _mem[1];
|
||||||
|
oldsize=_mem[2];
|
||||||
|
for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=0);
|
||||||
|
mem=(void *)(++_mem);
|
||||||
|
#endif
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
ret=realloc(mem, size);
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
|
ret=mspace_realloc((mstate) mspace, mem, size);
|
||||||
|
#endif
|
||||||
|
if(!ret)
|
||||||
|
{ /* Put it back the way it was */
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
for(; *_mem==0; *_mem++=*(size_t *) "NEDMALOC");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
_ret=(size_t *) ret;
|
||||||
|
ret=(void *)(_ret+3);
|
||||||
|
for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC";
|
||||||
|
_ret[0]=(size_t) mspace;
|
||||||
|
_ret[1]=size;
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE void CallFree(void *mspace, void *mem) THROWSPEC
|
||||||
|
{
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
mstate oldmspace=0;
|
||||||
|
size_t *_mem=(size_t *) mem-3, oldsize=0;
|
||||||
|
if(_mem[0]!=*(size_t *) "NEDMALOC")
|
||||||
|
{
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printf("*** nedmalloc frees system allocated block %p\n", mem);
|
||||||
|
#endif
|
||||||
|
free(mem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
oldmspace=(mstate) _mem[1];
|
||||||
|
oldsize=_mem[2];
|
||||||
|
for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=0);
|
||||||
|
mem=(void *)(++_mem);
|
||||||
|
#endif
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
free(mem);
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
|
mspace_free((mstate) mspace, mem);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
size_t nedblksize(void *mem) THROWSPEC
|
size_t nedblksize(void *mem) THROWSPEC
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
/* Only enable if testing with valgrind. Causes misoperation */
|
|
||||||
return THREADCACHEMAX;
|
|
||||||
#else
|
|
||||||
if(mem)
|
if(mem)
|
||||||
{
|
{
|
||||||
|
#if USE_MAGIC_HEADERS
|
||||||
|
size_t *_mem=(size_t *) mem-3;
|
||||||
|
if(_mem[0]==*(size_t *) "NEDMALOC")
|
||||||
|
{
|
||||||
|
mstate mspace=(mstate) _mem[1];
|
||||||
|
size_t size=_mem[2];
|
||||||
|
return size-3*sizeof(size_t);
|
||||||
|
}
|
||||||
|
else return 0;
|
||||||
|
#else
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
/* Fail everything */
|
||||||
|
return 0;
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
|
#ifdef WIN32
|
||||||
|
__try
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* We try to return zero here if it isn't one of our own blocks, however
|
||||||
|
the current block annotation scheme used by dlmalloc makes it impossible
|
||||||
|
to be absolutely sure of avoiding a segfault.
|
||||||
|
|
||||||
|
mchunkptr->prev_foot = mem-(2*size_t) = mstate ^ mparams.magic for PRECEDING block;
|
||||||
|
mchunkptr->head = mem-(1*size_t) = 8 multiple size of this block with bottom three bits = FLAG_BITS
|
||||||
|
*/
|
||||||
mchunkptr p=mem2chunk(mem);
|
mchunkptr p=mem2chunk(mem);
|
||||||
mstate fm = get_mstate_for(p);
|
mstate fm=0;
|
||||||
|
if(!is_inuse(p)) return 0;
|
||||||
|
/* The following isn't safe but is probably true: unlikely to allocate
|
||||||
|
a 2Gb block on a 32bit system or a 8Eb block on a 64 bit system */
|
||||||
|
if(p->head & ((size_t)1)<<(SIZE_T_BITSIZE-SIZE_T_ONE)) return 0;
|
||||||
|
/* We have now reduced our chances of being wrong to 0.5^4 = 6.25%.
|
||||||
|
We could start comparing prev_foot's for similarity but it starts getting slow. */
|
||||||
|
fm = get_mstate_for(p);
|
||||||
assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */
|
assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */
|
||||||
if(ok_magic(fm))
|
if(ok_magic(fm))
|
||||||
return chunksize(p)-overhead_for(p);
|
return chunksize(p)-overhead_for(p);
|
||||||
}
|
}
|
||||||
return 0;
|
#ifdef WIN32
|
||||||
|
__except(1) { }
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); }
|
void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); }
|
||||||
|
@ -244,8 +390,7 @@ static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#if 0
|
#if 0
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
unsigned asInt[2];
|
unsigned asInt[2];
|
||||||
double asDouble;
|
double asDouble;
|
||||||
};
|
};
|
||||||
|
@ -314,7 +459,6 @@ static void tcfullsanitycheck(threadcache *tc) THROWSPEC
|
||||||
|
|
||||||
static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC
|
static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(p);
|
|
||||||
#ifdef FULLSANITYCHECKS
|
#ifdef FULLSANITYCHECKS
|
||||||
tcfullsanitycheck(tc);
|
tcfullsanitycheck(tc);
|
||||||
#endif
|
#endif
|
||||||
|
@ -342,7 +486,7 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in
|
||||||
*tcbptr=0;
|
*tcbptr=0;
|
||||||
tc->freeInCache-=blksize;
|
tc->freeInCache-=blksize;
|
||||||
assert((long) tc->freeInCache>=0);
|
assert((long) tc->freeInCache>=0);
|
||||||
mspace_free(0, f);
|
CallFree(0, f);
|
||||||
/*tcsanitycheck(tcbptr);*/
|
/*tcsanitycheck(tcbptr);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,7 +510,7 @@ static void DestroyCaches(nedpool *p) THROWSPEC
|
||||||
assert(!tc->freeInCache);
|
assert(!tc->freeInCache);
|
||||||
tc->mymspace=-1;
|
tc->mymspace=-1;
|
||||||
tc->threadid=0;
|
tc->threadid=0;
|
||||||
mspace_free(0, tc);
|
CallFree(0, tc);
|
||||||
p->caches[n]=0;
|
p->caches[n]=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -384,7 +528,7 @@ static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC
|
||||||
RELEASE_LOCK(&p->mutex);
|
RELEASE_LOCK(&p->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
tc=p->caches[n]=(threadcache *) mspace_calloc(p->m[0], 1, sizeof(threadcache));
|
tc=p->caches[n]=(threadcache *) CallCalloc(p->m[0], 1, sizeof(threadcache), 0);
|
||||||
if(!tc)
|
if(!tc)
|
||||||
{
|
{
|
||||||
RELEASE_LOCK(&p->mutex);
|
RELEASE_LOCK(&p->mutex);
|
||||||
|
@ -409,7 +553,6 @@ static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROW
|
||||||
unsigned int idx=size2binidx(*size);
|
unsigned int idx=size2binidx(*size);
|
||||||
size_t blksize=0;
|
size_t blksize=0;
|
||||||
threadcacheblk *blk, **binsptr;
|
threadcacheblk *blk, **binsptr;
|
||||||
UNREFERENCED_PARAMETER(p);
|
|
||||||
#ifdef FULLSANITYCHECKS
|
#ifdef FULLSANITYCHECKS
|
||||||
tcfullsanitycheck(tc);
|
tcfullsanitycheck(tc);
|
||||||
#endif
|
#endif
|
||||||
|
@ -493,7 +636,6 @@ static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspac
|
||||||
{
|
{
|
||||||
unsigned int age=THREADCACHEMAXFREESPACE/8192;
|
unsigned int age=THREADCACHEMAXFREESPACE/8192;
|
||||||
/*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
|
/*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
|
||||||
UNREFERENCED_PARAMETER(mymspace);
|
|
||||||
while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
|
while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
|
||||||
{
|
{
|
||||||
RemoveCacheEntries(p, tc, age);
|
RemoveCacheEntries(p, tc, age);
|
||||||
|
@ -509,15 +651,8 @@ static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *me
|
||||||
threadcacheblk **binsptr, *tck=(threadcacheblk *) mem;
|
threadcacheblk **binsptr, *tck=(threadcacheblk *) mem;
|
||||||
assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
|
assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{ /* Make sure this is a valid memory block */
|
/* Make sure this is a valid memory block */
|
||||||
mchunkptr p = mem2chunk(mem);
|
assert(nedblksize(mem));
|
||||||
mstate fm = get_mstate_for(p);
|
|
||||||
if (!ok_magic(fm))
|
|
||||||
{
|
|
||||||
USAGE_ERROR_ACTION(fm, p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef FULLSANITYCHECKS
|
#ifdef FULLSANITYCHECKS
|
||||||
tcfullsanitycheck(tc);
|
tcfullsanitycheck(tc);
|
||||||
|
@ -543,7 +678,7 @@ static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *me
|
||||||
assert(idx<=THREADCACHEMAXBINS);
|
assert(idx<=THREADCACHEMAXBINS);
|
||||||
if(tck==*binsptr)
|
if(tck==*binsptr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Attempt to free already freed memory block %p - aborting!\n", tck);
|
fprintf(stderr, "nedmalloc: Attempt to free already freed memory block %p - aborting!\n", tck);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
#ifdef FULLSANITYCHECKS
|
#ifdef FULLSANITYCHECKS
|
||||||
|
@ -582,8 +717,12 @@ static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC
|
||||||
if(p->threads) goto done;
|
if(p->threads) goto done;
|
||||||
if(INITIAL_LOCK(&p->mutex)) goto err;
|
if(INITIAL_LOCK(&p->mutex)) goto err;
|
||||||
if(TLSALLOC(&p->mycache)) goto err;
|
if(TLSALLOC(&p->mycache)) goto err;
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
p->m[0]=(mstate) mspacecounter++;
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
|
if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
|
||||||
p->m[0]->extp=p;
|
p->m[0]->extp=p;
|
||||||
|
#endif
|
||||||
p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
|
p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
|
||||||
done:
|
done:
|
||||||
RELEASE_MALLOC_GLOBAL_LOCK();
|
RELEASE_MALLOC_GLOBAL_LOCK();
|
||||||
|
@ -594,7 +733,9 @@ err:
|
||||||
DestroyCaches(p);
|
DestroyCaches(p);
|
||||||
if(p->m[0])
|
if(p->m[0])
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
destroy_mspace(p->m[0]);
|
destroy_mspace(p->m[0]);
|
||||||
|
#endif
|
||||||
p->m[0]=0;
|
p->m[0]=0;
|
||||||
}
|
}
|
||||||
if(p->mycache)
|
if(p->mycache)
|
||||||
|
@ -622,8 +763,12 @@ if (TRY_LOCK(&p->m[n]->mutex)) goto found;
|
||||||
if(end<p->threads)
|
if(end<p->threads)
|
||||||
{
|
{
|
||||||
mstate temp;
|
mstate temp;
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
temp=(mstate) mspacecounter++;
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
if(!(temp=(mstate) create_mspace(size, 1)))
|
if(!(temp=(mstate) create_mspace(size, 1)))
|
||||||
goto badexit;
|
goto badexit;
|
||||||
|
#endif
|
||||||
/* Now we're ready to modify the lists, we lock */
|
/* Now we're ready to modify the lists, we lock */
|
||||||
ACQUIRE_LOCK(&p->mutex);
|
ACQUIRE_LOCK(&p->mutex);
|
||||||
while(p->m[end] && end<p->threads)
|
while(p->m[end] && end<p->threads)
|
||||||
|
@ -631,7 +776,9 @@ if (!(temp=(mstate) create_mspace(size, 1)))
|
||||||
if(end>=p->threads)
|
if(end>=p->threads)
|
||||||
{ /* Drat, must destroy it now */
|
{ /* Drat, must destroy it now */
|
||||||
RELEASE_LOCK(&p->mutex);
|
RELEASE_LOCK(&p->mutex);
|
||||||
destroy_mspace((mspace) temp);
|
#if USE_ALLOCATOR==1
|
||||||
|
destroy_mspace((mstate) temp);
|
||||||
|
#endif
|
||||||
goto badexit;
|
goto badexit;
|
||||||
}
|
}
|
||||||
/* We really want to make sure this goes into memory now but we
|
/* We really want to make sure this goes into memory now but we
|
||||||
|
@ -676,14 +823,16 @@ void neddestroypool(nedpool *p) THROWSPEC
|
||||||
DestroyCaches(p);
|
DestroyCaches(p);
|
||||||
for(n=0; p->m[n]; n++)
|
for(n=0; p->m[n]; n++)
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
destroy_mspace(p->m[n]);
|
destroy_mspace(p->m[n]);
|
||||||
|
#endif
|
||||||
p->m[n]=0;
|
p->m[n]=0;
|
||||||
}
|
}
|
||||||
RELEASE_LOCK(&p->mutex);
|
RELEASE_LOCK(&p->mutex);
|
||||||
if(TLSFREE(p->mycache)) abort();
|
if(TLSFREE(p->mycache)) abort();
|
||||||
nedpfree(0, p);
|
nedpfree(0, p);
|
||||||
}
|
}
|
||||||
void neddestroysyspool(void) THROWSPEC
|
void neddestroysyspool() THROWSPEC
|
||||||
{
|
{
|
||||||
nedpool *p=&syspool;
|
nedpool *p=&syspool;
|
||||||
int n;
|
int n;
|
||||||
|
@ -691,14 +840,16 @@ void neddestroysyspool(void) THROWSPEC
|
||||||
DestroyCaches(p);
|
DestroyCaches(p);
|
||||||
for(n=0; p->m[n]; n++)
|
for(n=0; p->m[n]; n++)
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
destroy_mspace(p->m[n]);
|
destroy_mspace(p->m[n]);
|
||||||
|
#endif
|
||||||
p->m[n]=0;
|
p->m[n]=0;
|
||||||
}
|
}
|
||||||
/* Render syspool unusable */
|
/* Render syspool unusable */
|
||||||
for(n=0; n<THREADCACHEMAXCACHES; n++)
|
for(n=0; n<THREADCACHEMAXCACHES; n++)
|
||||||
p->caches[n]=(threadcache *) 0xdeadbeef;
|
p->caches[n]=(threadcache *)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeef : 0xdeadbeef);
|
||||||
for(n=0; n<MAXTHREADSINPOOL+1; n++)
|
for(n=0; n<MAXTHREADSINPOOL+1; n++)
|
||||||
p->m[n]=(mstate) 0xdeadbeef;
|
p->m[n]=(mstate)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeef : 0xdeadbeef);
|
||||||
if(TLSFREE(p->mycache)) abort();
|
if(TLSFREE(p->mycache)) abort();
|
||||||
RELEASE_LOCK(&p->mutex);
|
RELEASE_LOCK(&p->mutex);
|
||||||
}
|
}
|
||||||
|
@ -740,7 +891,7 @@ void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC
|
||||||
mycache=(int)(size_t) TLSGET(p->mycache);
|
mycache=(int)(size_t) TLSGET(p->mycache);
|
||||||
if(!mycache)
|
if(!mycache)
|
||||||
{ /* Set to mspace 0 */
|
{ /* Set to mspace 0 */
|
||||||
if (disable && TLSSET(p->mycache, (void *)-1)) abort();
|
if(disable && TLSSET(p->mycache, (void *)(size_t)-1)) abort();
|
||||||
}
|
}
|
||||||
else if(mycache>0)
|
else if(mycache>0)
|
||||||
{ /* Set to last used mspace */
|
{ /* Set to last used mspace */
|
||||||
|
@ -757,7 +908,7 @@ void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC
|
||||||
{
|
{
|
||||||
tc->mymspace=-1;
|
tc->mymspace=-1;
|
||||||
tc->threadid=0;
|
tc->threadid=0;
|
||||||
mspace_free(0, p->caches[mycache-1]);
|
CallFree(0, p->caches[mycache-1]);
|
||||||
p->caches[mycache-1]=0;
|
p->caches[mycache-1]=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -772,15 +923,17 @@ void neddisablethreadcache(nedpool *p) THROWSPEC
|
||||||
{ \
|
{ \
|
||||||
mstate m = GetMSpace((p),(tc),(ms),(s)); \
|
mstate m = GetMSpace((p),(tc),(ms),(s)); \
|
||||||
action; \
|
action; \
|
||||||
RELEASE_LOCK(&m->mutex); \
|
if(USE_ALLOCATOR==1) { RELEASE_LOCK(&m->mutex); } \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC
|
static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC
|
||||||
{ /* Returns a locked and ready for use mspace */
|
{ /* Returns a locked and ready for use mspace */
|
||||||
mstate m=p->m[mymspace];
|
mstate m=p->m[mymspace];
|
||||||
assert(m);
|
assert(m);
|
||||||
if (!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size); \
|
#if USE_ALLOCATOR==1
|
||||||
|
if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);
|
||||||
/*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/
|
/*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/
|
||||||
|
#endif
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC
|
static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC
|
||||||
|
@ -803,7 +956,7 @@ static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymsp
|
||||||
*tc=AllocCache(*p);
|
*tc=AllocCache(*p);
|
||||||
if(!*tc)
|
if(!*tc)
|
||||||
{ /* Disable */
|
{ /* Disable */
|
||||||
if (TLSSET((*p)->mycache, (void *)-1)) abort();
|
if(TLSSET((*p)->mycache, (void *)(size_t)-1)) abort();
|
||||||
*mymspace=0;
|
*mymspace=0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -842,7 +995,7 @@ NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
|
||||||
if(!ret)
|
if(!ret)
|
||||||
{ /* Use this thread's mspace */
|
{ /* Use this thread's mspace */
|
||||||
GETMSPACE(m, p, tc, mymspace, size,
|
GETMSPACE(m, p, tc, mymspace, size,
|
||||||
ret=mspace_malloc(m, size));
|
ret=CallMalloc(m, size, 0));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -863,7 +1016,7 @@ NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
|
||||||
if(!ret)
|
if(!ret)
|
||||||
{ /* Use this thread's mspace */
|
{ /* Use this thread's mspace */
|
||||||
GETMSPACE(m, p, tc, mymspace, rsize,
|
GETMSPACE(m, p, tc, mymspace, rsize,
|
||||||
ret=mspace_calloc(m, 1, rsize));
|
ret=CallCalloc(m, 1, rsize, 0));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -878,21 +1031,28 @@ NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPE
|
||||||
if(tc && size && size<=THREADCACHEMAX)
|
if(tc && size && size<=THREADCACHEMAX)
|
||||||
{ /* Use the thread cache */
|
{ /* Use the thread cache */
|
||||||
size_t memsize=nedblksize(mem);
|
size_t memsize=nedblksize(mem);
|
||||||
|
#if !USE_MAGIC_HEADERS
|
||||||
assert(memsize);
|
assert(memsize);
|
||||||
|
if(!memsize)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "nedmalloc: nedprealloc() called with a block not created by nedmalloc!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if((ret=threadcache_malloc(p, tc, &size)))
|
if((ret=threadcache_malloc(p, tc, &size)))
|
||||||
{
|
{
|
||||||
memcpy(ret, mem, memsize<size ? memsize : size);
|
memcpy(ret, mem, memsize<size ? memsize : size);
|
||||||
if (memsize<=THREADCACHEMAX)
|
if(memsize && memsize<=THREADCACHEMAX)
|
||||||
threadcache_free(p, tc, mymspace, mem, memsize);
|
threadcache_free(p, tc, mymspace, mem, memsize);
|
||||||
else
|
else
|
||||||
mspace_free(0, mem);
|
CallFree(0, mem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(!ret)
|
if(!ret)
|
||||||
{ /* Reallocs always happen in the mspace they happened in, so skip
|
{ /* Reallocs always happen in the mspace they happened in, so skip
|
||||||
locking the preferred mspace for this thread */
|
locking the preferred mspace for this thread */
|
||||||
ret=mspace_realloc(0, mem, size);
|
ret=CallRealloc(0, mem, size);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -902,24 +1062,29 @@ void nedpfree(nedpool *p, void *mem) THROWSPEC
|
||||||
threadcache *tc;
|
threadcache *tc;
|
||||||
int mymspace;
|
int mymspace;
|
||||||
size_t memsize;
|
size_t memsize;
|
||||||
assert(mem);
|
|
||||||
if(!mem)
|
if(!mem)
|
||||||
{ /* You'd be surprised the number of times this happens as so many
|
{ /* You'd be surprised the number of times this happens as so many
|
||||||
allocators are non-conformant here */
|
allocators are non-conformant here */
|
||||||
fprintf(stderr, "nedpfree() called with zero!\n");
|
fprintf(stderr, "nedmalloc: WARNING nedpfree() called with zero. This is not portable behaviour!\n");
|
||||||
abort();
|
return;
|
||||||
}
|
}
|
||||||
GetThreadCache(&p, &tc, &mymspace, 0);
|
GetThreadCache(&p, &tc, &mymspace, 0);
|
||||||
#if THREADCACHEMAX
|
#if THREADCACHEMAX
|
||||||
memsize=nedblksize(mem);
|
memsize=nedblksize(mem);
|
||||||
|
#if !USE_MAGIC_HEADERS
|
||||||
assert(memsize);
|
assert(memsize);
|
||||||
if (mem && tc && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
|
if(!memsize)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "nedmalloc: nedpfree() called with a block not created by nedmalloc!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(mem && tc && memsize && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
|
||||||
threadcache_free(p, tc, mymspace, mem, memsize);
|
threadcache_free(p, tc, mymspace, mem, memsize);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
mspace_free(0, mem);
|
CallFree(0, mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
|
NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
@ -928,19 +1093,19 @@ NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes)
|
||||||
GetThreadCache(&p, &tc, &mymspace, &bytes);
|
GetThreadCache(&p, &tc, &mymspace, &bytes);
|
||||||
{ /* Use this thread's mspace */
|
{ /* Use this thread's mspace */
|
||||||
GETMSPACE(m, p, tc, mymspace, bytes,
|
GETMSPACE(m, p, tc, mymspace, bytes,
|
||||||
ret=mspace_memalign(m, alignment, bytes));
|
ret=CallMalloc(m, bytes, alignment));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !NO_MALLINFO
|
#if !NO_MALLINFO
|
||||||
struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC
|
struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
struct mallinfo ret={0,0,0,0,0,0,0,0,0,0};
|
struct mallinfo ret={0};
|
||||||
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
||||||
for(n=0; p->m[n]; n++)
|
for(n=0; p->m[n]; n++)
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
struct mallinfo t=mspace_mallinfo(p->m[n]);
|
struct mallinfo t=mspace_mallinfo(p->m[n]);
|
||||||
ret.arena+=t.arena;
|
ret.arena+=t.arena;
|
||||||
ret.ordblks+=t.ordblks;
|
ret.ordblks+=t.ordblks;
|
||||||
|
@ -949,14 +1114,30 @@ struct mallinfo t=mspace_mallinfo(p->m[n]);
|
||||||
ret.uordblks+=t.uordblks;
|
ret.uordblks+=t.uordblks;
|
||||||
ret.fordblks+=t.fordblks;
|
ret.fordblks+=t.fordblks;
|
||||||
ret.keepcost+=t.keepcost;
|
ret.keepcost+=t.keepcost;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
|
int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(p);
|
#if USE_ALLOCATOR==1
|
||||||
return mspace_mallopt(parno, value);
|
return mspace_mallopt(parno, value);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC
|
||||||
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
|
if(granularity) *granularity=mparams.granularity;
|
||||||
|
if(magic) *magic=mparams.magic;
|
||||||
|
return (void *) &syspool;
|
||||||
|
#else
|
||||||
|
if(granularity) *granularity=0;
|
||||||
|
if(magic) *magic=0;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
|
int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
|
||||||
{
|
{
|
||||||
|
@ -964,7 +1145,9 @@ int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
|
||||||
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
||||||
for(n=0; p->m[n]; n++)
|
for(n=0; p->m[n]; n++)
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
ret+=mspace_trim(p->m[n], pad);
|
ret+=mspace_trim(p->m[n], pad);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -974,7 +1157,9 @@ void nedpmalloc_stats(nedpool *p) THROWSPEC
|
||||||
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
||||||
for(n=0; p->m[n]; n++)
|
for(n=0; p->m[n]; n++)
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
mspace_malloc_stats(p->m[n]);
|
mspace_malloc_stats(p->m[n]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
|
size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
|
||||||
|
@ -984,7 +1169,9 @@ size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
|
||||||
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
|
||||||
for(n=0; p->m[n]; n++)
|
for(n=0; p->m[n]; n++)
|
||||||
{
|
{
|
||||||
|
#if USE_ALLOCATOR==1
|
||||||
ret+=mspace_footprint(p->m[n]);
|
ret+=mspace_footprint(p->m[n]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -994,8 +1181,13 @@ NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_
|
||||||
threadcache *tc;
|
threadcache *tc;
|
||||||
int mymspace;
|
int mymspace;
|
||||||
GetThreadCache(&p, &tc, &mymspace, &elemsize);
|
GetThreadCache(&p, &tc, &mymspace, &elemsize);
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
|
||||||
|
ret=unsupported_operation("independent_calloc"));
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
|
GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
|
||||||
ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
|
ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
|
NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
|
||||||
|
@ -1008,8 +1200,13 @@ NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_
|
||||||
for(i=0; i<elems; i++)
|
for(i=0; i<elems; i++)
|
||||||
adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
|
adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
|
||||||
GetThreadCache(&p, &tc, &mymspace, 0);
|
GetThreadCache(&p, &tc, &mymspace, 0);
|
||||||
|
#if USE_ALLOCATOR==0
|
||||||
|
GETMSPACE(m, p, tc, mymspace, 0,
|
||||||
|
ret=unsupported_operation("independent_comalloc"));
|
||||||
|
#elif USE_ALLOCATOR==1
|
||||||
GETMSPACE(m, p, tc, mymspace, 0,
|
GETMSPACE(m, p, tc, mymspace, 0,
|
||||||
ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
|
ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue