update nedmalloc to r1116

git-svn-id: https://svn.eduke32.com/eduke32@1509 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
terminx 2009-09-30 22:19:57 +00:00
parent 5ea5f4bc9b
commit dcd7c3c9fe
4 changed files with 1275 additions and 942 deletions

View file

@ -35,7 +35,9 @@
#endif
#endif
#define REPLACE_SYSTEM_ALLOCATOR
#define USE_ALLOCATOR 1
#define REPLACE_SYSTEM_ALLOCATOR 1
#define USE_MAGIC_HEADERS 1
#include "nedmalloc.h"
#ifndef TRUE

View file

@ -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
usually is) a function rather than a constant. This is ignored
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)
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,
system_info.dwAllocationGranularity in WIN32,
GetLargePageMinimum() if ENABLE_LARGE_PAGES,
otherwise 64K.
Also settable using mallopt(M_GRANULARITY, x)
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
"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
Also settable using mallopt(M_TRIM_THRESHOLD, x)
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
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#define HAVE_MMAP 1
#define HAVE_MORECORE 0
#define LACKS_UNISTD_H
@ -1262,7 +1284,7 @@ int mspace_mallopt(int, int);
#endif /* MSPACES */
#ifdef __cplusplus
}; /* end of extern "C" */
} /* end of extern "C" */
#endif /* __cplusplus */
/*
@ -1277,10 +1299,8 @@ int mspace_mallopt(int, int);
/*------------------------------ internal #includes ---------------------- */
#ifdef WIN32
#ifndef __GNUC__
#if defined(WIN32) && defined(_MSC_VER)
#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
#endif
#endif /* WIN32 */
#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 :\
((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 ------------------------- */
/*
@ -1532,14 +1575,41 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
#if HAVE_MMAP
#ifndef WIN32
#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
#define MMAP_PROT (PROT_READ|PROT_WRITE)
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS 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
#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 */
/*
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. */
#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
(dev_zero_fd = open("/dev/zero", O_RDWR), \
mmap(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)) : \
MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
#endif /* MAP_ANONYMOUS */
#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 */
/* 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) {
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;
}
@ -1823,15 +1936,14 @@ static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) {
int spins = 0;
for (;;) {
if (sl->l != 0) {
if (sl->threadid == (signed)CURRENT_THREAD) {
if (sl->threadid == CURRENT_THREAD) {
++sl->c;
return 0;
}
}
else {
if (!interlockedexchange(&sl->l, 1)) {
assert(!sl->1855
);
assert(!sl->threadid);
sl->threadid = CURRENT_THREAD;
sl->c = 1;
return 0;
@ -1853,7 +1965,7 @@ static FORCEINLINE void win32_release_lock (MLOCK_T *sl) {
static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
if (sl->l != 0) {
if (sl->threadid == (signed)CURRENT_THREAD) {
if (sl->threadid == CURRENT_THREAD) {
++sl->c;
return 1;
}
@ -2120,7 +2232,6 @@ typedef struct malloc_chunk* mchunkptr;
typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
typedef unsigned int bindex_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 ----------------------- */
@ -2513,10 +2624,10 @@ struct malloc_state {
size_t footprint;
size_t max_footprint;
flag_t mflags;
msegment seg;
#if USE_LOCKS
MLOCK_T mutex; /* locate lock among fields that rarely change */
#endif /* USE_LOCKS */
msegment seg;
void* extp; /* Unused but available for extensions */
size_t exts;
};
@ -2525,27 +2636,6 @@ typedef struct malloc_state* mstate;
/* ------------- 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
/* The global malloc_state used for all non-"mspace" calls */
@ -2734,7 +2824,7 @@ static size_t traverse_and_check(mstate m);
/* ---------------------------- Indexing Bins ---------------------------- */
#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 MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
@ -2782,7 +2872,7 @@ static size_t traverse_and_check(mstate m);
I = NTREEBINS-1;\
else {\
unsigned int K;\
_BitScanReverse((DWORD *) &K, X);\
_BitScanReverse((DWORD *) &K, (DWORD) X);\
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 -------------------------- */
#ifdef ENABLE_LARGE_PAGES
typedef size_t (WINAPI *GetLargePageMinimum_t)(void);
#endif
/* Initialize mparams */
static int init_mparams(void) {
#ifdef NEED_GLOBAL_LOCK_INIT
@ -3026,6 +3120,20 @@ static int init_mparams(void) {
psize = system_info.dwPageSize;
gsize = ((DEFAULT_GRANULARITY != 0)?
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 */
@ -5465,6 +5573,7 @@ int mspace_mallopt(int param_number, int value) {
#endif /* MSPACES */
/* -------------------- Alternative MORECORE functions ------------------- */
/*
@ -5753,4 +5862,3 @@ History:
*/

View file

@ -1,5 +1,5 @@
/* 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
@ -29,8 +29,6 @@ DEALINGS IN THE SOFTWARE.
#ifndef NEDMALLOC_H
#define NEDMALLOC_H
#define THREADCACHEMAX 65536
#define THREADCACHEMAXFREESPACE (1024*1024*4)
/* 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
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
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,
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 */
#ifndef EXTSPEC
#define EXTSPEC extern
#ifndef NEDMALLOCEXTSPEC
#ifdef NEDMALLOC_DLL_EXPORTS
#define NEDMALLOCEXTSPEC extern __declspec(dllexport)
#else
#define NEDMALLOCEXTSPEC extern
#endif
#endif
#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
#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
#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 nedcalloc calloc
#define nedrealloc realloc
@ -82,12 +111,8 @@ ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
#define nedblksize _msize
#endif
#endif
#endif
#ifndef _MSC_VER
#ifndef UNREFERENCED_PARAMETER
#define UNREFERENCED_PARAMETER(x) x=x
#endif
#endif
#ifndef NO_MALLINFO
#define NO_MALLINFO 0
@ -117,33 +142,36 @@ extern "C" {
/* These are the global functions */
/* 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;
EXTSPEC NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
EXTSPEC void nedfree(void *mem) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
NEDMALLOCEXTSPEC void nedfree(void *mem) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
#if !NO_MALLINFO
EXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC;
NEDMALLOCEXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC;
#endif
EXTSPEC int nedmallopt(int parno, int value) THROWSPEC;
EXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC;
EXTSPEC void nedmalloc_stats(void) THROWSPEC;
EXTSPEC size_t nedmalloc_footprint(void) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
NEDMALLOCEXTSPEC int nedmallopt(int parno, int value) THROWSPEC;
NEDMALLOCEXTSPEC void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC;
NEDMALLOCEXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC;
NEDMALLOCEXTSPEC void nedmalloc_stats(void) THROWSPEC;
NEDMALLOCEXTSPEC size_t nedmalloc_footprint(void) 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.
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
get a fatal exception!
*/
EXTSPEC void neddestroysyspool(void) THROWSPEC;
NEDMALLOCEXTSPEC void neddestroysyspool() THROWSPEC;
/* These are the pool functions */
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
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().
*/
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
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.
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
data to the central pool. Remember to ALWAYS call with zero if you used the
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
data to the central pool. Remember to ALWAYS call with zero if you used the
system pool.
*/
EXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
NEDMALLOCEXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
EXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
EXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
NEDMALLOCEXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
#if !NO_MALLINFO
EXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC;
NEDMALLOCEXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC;
#endif
EXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
EXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
EXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
EXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
EXTSPEC 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 int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
NEDMALLOCEXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
NEDMALLOCEXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
NEDMALLOCEXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
#if defined(__cplusplus)
}
#endif
#undef EXTSPEC
#endif

View file

@ -1,5 +1,5 @@
/* 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
@ -36,14 +36,20 @@ DEALINGS IN THE SOFTWARE.
#endif
/*#define FULLSANITYCHECKS*/
#define USE_ALLOCATOR 1
#define REPLACE_SYSTEM_ALLOCATOR 1
#define USE_MAGIC_HEADERS 1
#include "nedmalloc.h"
#ifdef _WIN32
#ifdef WIN32
#include <malloc.h>
#include <stddef.h>
#endif
#if USE_ALLOCATOR==1
#define MSPACES 1
#define ONLY_MSPACES 1
#endif
#define USE_DL_PREFIX 1
#ifndef USE_LOCKS
#define USE_LOCKS 1
#endif
@ -65,6 +71,9 @@ DEALINGS IN THE SOFTWARE.
/* The default of 64Kb means we spend too much time kernel-side */
#ifndef DEFAULT_GRANULARITY
#define DEFAULT_GRANULARITY (1*1024*1024)
#if DEBUG
#define DEFAULT_GRANULARITY_ALIGNED
#endif
#endif
/*#define USE_SPIN_LOCKS 0*/
@ -88,30 +97,18 @@ DEALINGS IN THE SOFTWARE.
#endif
/* The maximum size to be allocated from the thread cache */
#ifndef THREADCACHEMAX
#define THREADCACHEMAX 8192
#define THREADCACHEMAX 65536
#endif
#if 1
/* 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)
#else
#error undefined size
#endif
#else
/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
#if THREADCACHEMAX == 8192
#define THREADCACHEMAXBINS (13-4)
#elif THREADCACHEMAX == 65536
#define THREADCACHEMAXBINS (16-4)
#else
#error undefined size
#endif
#endif
/* Point at which the free space in a thread cache is garbage collected */
#ifndef THREADCACHEMAXFREESPACE
#define THREADCACHEMAXFREESPACE (512*1024)
#define THREADCACHEMAXFREESPACE (512*1024*8)
#endif
@ -139,41 +136,190 @@ static LPVOID ChkedTlsGetValue(DWORD idx)
#define TLSSET(k, a) pthread_setspecific(k, a)
#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(NO_NED_NAMESPACE)
namespace nedalloc
{
namespace nedalloc {
#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
#if USE_ALLOCATOR==0
ret=malloc(size);
#elif USE_ALLOCATOR==1
ret=mspace_malloc((mstate) mspace, 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 *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
{
#if 0
/* Only enable if testing with valgrind. Causes misoperation */
return THREADCACHEMAX;
#else
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);
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 */
if(ok_magic(fm))
return chunksize(p)-overhead_for(p);
}
return 0;
#ifdef WIN32
__except(1) { }
#endif
#endif
#endif
}
return 0;
}
void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); }
@ -244,8 +390,7 @@ static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC
}
#else
#if 0
union
{
union {
unsigned asInt[2];
double asDouble;
};
@ -314,7 +459,6 @@ static void tcfullsanitycheck(threadcache *tc) THROWSPEC
static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC
{
UNREFERENCED_PARAMETER(p);
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
@ -342,7 +486,7 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in
*tcbptr=0;
tc->freeInCache-=blksize;
assert((long) tc->freeInCache>=0);
mspace_free(0, f);
CallFree(0, f);
/*tcsanitycheck(tcbptr);*/
}
}
@ -366,7 +510,7 @@ static void DestroyCaches(nedpool *p) THROWSPEC
assert(!tc->freeInCache);
tc->mymspace=-1;
tc->threadid=0;
mspace_free(0, tc);
CallFree(0, tc);
p->caches[n]=0;
}
}
@ -384,7 +528,7 @@ static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC
RELEASE_LOCK(&p->mutex);
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)
{
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);
size_t blksize=0;
threadcacheblk *blk, **binsptr;
UNREFERENCED_PARAMETER(p);
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
@ -493,7 +636,6 @@ static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspac
{
unsigned int age=THREADCACHEMAXFREESPACE/8192;
/*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
UNREFERENCED_PARAMETER(mymspace);
while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
{
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;
assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
#ifdef DEBUG
{ /* Make sure this is a valid memory block */
mchunkptr p = mem2chunk(mem);
mstate fm = get_mstate_for(p);
if (!ok_magic(fm))
{
USAGE_ERROR_ACTION(fm, p);
return;
}
}
/* Make sure this is a valid memory block */
assert(nedblksize(mem));
#endif
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
@ -543,7 +678,7 @@ static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *me
assert(idx<=THREADCACHEMAXBINS);
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();
}
#ifdef FULLSANITYCHECKS
@ -582,8 +717,12 @@ static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC
if(p->threads) goto done;
if(INITIAL_LOCK(&p->mutex)) 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;
p->m[0]->extp=p;
#endif
p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
done:
RELEASE_MALLOC_GLOBAL_LOCK();
@ -594,7 +733,9 @@ err:
DestroyCaches(p);
if(p->m[0])
{
#if USE_ALLOCATOR==1
destroy_mspace(p->m[0]);
#endif
p->m[0]=0;
}
if(p->mycache)
@ -622,8 +763,12 @@ if (TRY_LOCK(&p->m[n]->mutex)) goto found;
if(end<p->threads)
{
mstate temp;
#if USE_ALLOCATOR==0
temp=(mstate) mspacecounter++;
#elif USE_ALLOCATOR==1
if(!(temp=(mstate) create_mspace(size, 1)))
goto badexit;
#endif
/* Now we're ready to modify the lists, we lock */
ACQUIRE_LOCK(&p->mutex);
while(p->m[end] && end<p->threads)
@ -631,7 +776,9 @@ if (!(temp=(mstate) create_mspace(size, 1)))
if(end>=p->threads)
{ /* Drat, must destroy it now */
RELEASE_LOCK(&p->mutex);
destroy_mspace((mspace) temp);
#if USE_ALLOCATOR==1
destroy_mspace((mstate) temp);
#endif
goto badexit;
}
/* We really want to make sure this goes into memory now but we
@ -676,14 +823,16 @@ void neddestroypool(nedpool *p) THROWSPEC
DestroyCaches(p);
for(n=0; p->m[n]; n++)
{
#if USE_ALLOCATOR==1
destroy_mspace(p->m[n]);
#endif
p->m[n]=0;
}
RELEASE_LOCK(&p->mutex);
if(TLSFREE(p->mycache)) abort();
nedpfree(0, p);
}
void neddestroysyspool(void) THROWSPEC
void neddestroysyspool() THROWSPEC
{
nedpool *p=&syspool;
int n;
@ -691,14 +840,16 @@ void neddestroysyspool(void) THROWSPEC
DestroyCaches(p);
for(n=0; p->m[n]; n++)
{
#if USE_ALLOCATOR==1
destroy_mspace(p->m[n]);
#endif
p->m[n]=0;
}
/* Render syspool unusable */
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++)
p->m[n]=(mstate) 0xdeadbeef;
p->m[n]=(mstate)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeef : 0xdeadbeef);
if(TLSFREE(p->mycache)) abort();
RELEASE_LOCK(&p->mutex);
}
@ -740,7 +891,7 @@ void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC
mycache=(int)(size_t) TLSGET(p->mycache);
if(!mycache)
{ /* 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)
{ /* Set to last used mspace */
@ -757,7 +908,7 @@ void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC
{
tc->mymspace=-1;
tc->threadid=0;
mspace_free(0, p->caches[mycache-1]);
CallFree(0, p->caches[mycache-1]);
p->caches[mycache-1]=0;
}
}
@ -772,15 +923,17 @@ void neddisablethreadcache(nedpool *p) THROWSPEC
{ \
mstate m = GetMSpace((p),(tc),(ms),(s)); \
action; \
RELEASE_LOCK(&m->mutex); \
if(USE_ALLOCATOR==1) { RELEASE_LOCK(&m->mutex); } \
} while (0)
static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC
{ /* Returns a locked and ready for use mspace */
mstate m=p->m[mymspace];
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));*/
#endif
return m;
}
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);
if(!*tc)
{ /* Disable */
if (TLSSET((*p)->mycache, (void *)-1)) abort();
if(TLSSET((*p)->mycache, (void *)(size_t)-1)) abort();
*mymspace=0;
}
else
@ -842,7 +995,7 @@ NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
if(!ret)
{ /* Use this thread's mspace */
GETMSPACE(m, p, tc, mymspace, size,
ret=mspace_malloc(m, size));
ret=CallMalloc(m, size, 0));
}
return ret;
}
@ -863,7 +1016,7 @@ NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
if(!ret)
{ /* Use this thread's mspace */
GETMSPACE(m, p, tc, mymspace, rsize,
ret=mspace_calloc(m, 1, rsize));
ret=CallCalloc(m, 1, rsize, 0));
}
return ret;
}
@ -878,21 +1031,28 @@ NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPE
if(tc && size && size<=THREADCACHEMAX)
{ /* Use the thread cache */
size_t memsize=nedblksize(mem);
#if !USE_MAGIC_HEADERS
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)))
{
memcpy(ret, mem, memsize<size ? memsize : size);
if (memsize<=THREADCACHEMAX)
if(memsize && memsize<=THREADCACHEMAX)
threadcache_free(p, tc, mymspace, mem, memsize);
else
mspace_free(0, mem);
CallFree(0, mem);
}
}
#endif
if(!ret)
{ /* Reallocs always happen in the mspace they happened in, so skip
locking the preferred mspace for this thread */
ret=mspace_realloc(0, mem, size);
ret=CallRealloc(0, mem, size);
}
return ret;
}
@ -902,24 +1062,29 @@ void nedpfree(nedpool *p, void *mem) THROWSPEC
threadcache *tc;
int mymspace;
size_t memsize;
assert(mem);
if(!mem)
{ /* You'd be surprised the number of times this happens as so many
allocators are non-conformant here */
fprintf(stderr, "nedpfree() called with zero!\n");
abort();
fprintf(stderr, "nedmalloc: WARNING nedpfree() called with zero. This is not portable behaviour!\n");
return;
}
GetThreadCache(&p, &tc, &mymspace, 0);
#if THREADCACHEMAX
memsize=nedblksize(mem);
#if !USE_MAGIC_HEADERS
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);
else
#endif
mspace_free(0, mem);
CallFree(0, mem);
}
NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
{
void *ret;
@ -928,19 +1093,19 @@ NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes)
GetThreadCache(&p, &tc, &mymspace, &bytes);
{ /* Use this thread's mspace */
GETMSPACE(m, p, tc, mymspace, bytes,
ret=mspace_memalign(m, alignment, bytes));
ret=CallMalloc(m, bytes, alignment));
}
return ret;
}
#if !NO_MALLINFO
struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC
{
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); }
for(n=0; p->m[n]; n++)
{
#if USE_ALLOCATOR==1
struct mallinfo t=mspace_mallinfo(p->m[n]);
ret.arena+=t.arena;
ret.ordblks+=t.ordblks;
@ -949,14 +1114,30 @@ struct mallinfo t=mspace_mallinfo(p->m[n]);
ret.uordblks+=t.uordblks;
ret.fordblks+=t.fordblks;
ret.keepcost+=t.keepcost;
#endif
}
return ret;
}
#endif
int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
{
UNREFERENCED_PARAMETER(p);
#if USE_ALLOCATOR==1
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
{
@ -964,7 +1145,9 @@ int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
for(n=0; p->m[n]; n++)
{
#if USE_ALLOCATOR==1
ret+=mspace_trim(p->m[n], pad);
#endif
}
return ret;
}
@ -974,7 +1157,9 @@ void nedpmalloc_stats(nedpool *p) THROWSPEC
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
for(n=0; p->m[n]; n++)
{
#if USE_ALLOCATOR==1
mspace_malloc_stats(p->m[n]);
#endif
}
}
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); }
for(n=0; p->m[n]; n++)
{
#if USE_ALLOCATOR==1
ret+=mspace_footprint(p->m[n]);
#endif
}
return ret;
}
@ -994,8 +1181,13 @@ NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_
threadcache *tc;
int mymspace;
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,
ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
#endif
return ret;
}
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++)
adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
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,
ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
#endif
return ret;
}