123 lines
3.5 KiB
C++
123 lines
3.5 KiB
C++
|
|
// We only use a custom allocator on linux (for now)
|
|
// The allocator we chose is 'dlmalloc' (doug lea's malloc).
|
|
// It's a good allocator for single-threaded programs.
|
|
// It needs to be configured by setting a bunch of defines.
|
|
//
|
|
#ifdef __linux__
|
|
|
|
// We need this to define dlmalloc, not malloc.
|
|
#define USE_DL_PREFIX 1
|
|
|
|
// We don't need mspaces.
|
|
#define ONLY_MSPACES 0
|
|
#define MSPACES 0
|
|
|
|
// We don't need mallinfo
|
|
#define NO_MALLINFO 1
|
|
|
|
// We don't need dlmalloc_inspect_all
|
|
#define MALLOC_INSPECT_ALL 0
|
|
|
|
// Disable locking. The entire engine is single-threaded.
|
|
#define USE_LOCKS 0
|
|
|
|
// This allocator can use sbrk to obtain RAM. We're going to
|
|
// emulate sbrk, in order to put it in a different memory region
|
|
// than the system malloc, which also uses sbrk.
|
|
#define HAVE_MORECORE 1
|
|
#define MORECORE emulated_sbrk
|
|
#define MORECORE_CANNOT_TRIM 1
|
|
|
|
// We won't let the memory allocator use mmap. This is because
|
|
// opening the replay log may be implemented in stdio using mmap.
|
|
// So using mmap might trigger different results under replay.
|
|
#define HAVE_MMAP 0
|
|
|
|
// Fix a warning in dlmalloc.
|
|
#define MAX_RELEASE_CHECK_RATE INT_MAX
|
|
|
|
// Don't generate random seeds, or time-based seeds.
|
|
#define USE_DEV_RANDOM 0
|
|
#define LACKS_TIME_H 1
|
|
|
|
// Don't export any dlmalloc functions.
|
|
#define DLMALLOC_EXPORT static inline
|
|
|
|
#include <sys/mman.h>
|
|
#include <cstdint>
|
|
#include <cassert>
|
|
#include <climits>
|
|
|
|
static char *emulated_sbrk_base;
|
|
static intptr_t emulated_sbrk_used;
|
|
static intptr_t emulated_sbrk_limit;
|
|
|
|
// We assume that the increments are already aligned to the system
|
|
// page size, because dlmalloc does that for us.
|
|
//
|
|
// Our emulated sbrk cannot trim the memory size. It can only grow.
|
|
//
|
|
static void *emulated_sbrk(intptr_t increment) {
|
|
if (emulated_sbrk_base == 0) {
|
|
emulated_sbrk_limit = intptr_t(64) * 1024 * 1024 * 1024;
|
|
void *map = mmap(nullptr, emulated_sbrk_limit, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
assert(map != MAP_FAILED);
|
|
assert(map != nullptr);
|
|
emulated_sbrk_base = (char *)map;
|
|
emulated_sbrk_used = 0;
|
|
}
|
|
int64_t old_used = emulated_sbrk_used;
|
|
int64_t new_used = emulated_sbrk_used + increment;
|
|
if (new_used > emulated_sbrk_limit) {
|
|
return (void *)(-1);
|
|
}
|
|
assert(new_used >= old_used);
|
|
emulated_sbrk_used = new_used;
|
|
if (new_used > old_used) {
|
|
int status = mprotect(emulated_sbrk_base + old_used, new_used - old_used, PROT_READ | PROT_WRITE);
|
|
assert(status == 0);
|
|
}
|
|
return emulated_sbrk_base + old_used;
|
|
}
|
|
|
|
#include "dlmalloc/dlmalloc.c"
|
|
|
|
namespace eng {
|
|
static uint32_t hash;
|
|
void *malloc(size_t size) {
|
|
void *result = dlmalloc(size);
|
|
hash += uint32_t(uintptr_t(result)) + 0x83748374;
|
|
hash += hash << 10;
|
|
hash ^= hash >> 6;
|
|
hash += uint32_t(size) + 0x85893489;
|
|
hash += hash << 10;
|
|
hash ^= hash >> 6;
|
|
return result;
|
|
}
|
|
void *realloc(void *p, size_t size) {
|
|
void *result = dlrealloc(p, size);
|
|
hash += uint32_t(uintptr_t(p)) + 0x74741912;
|
|
hash += hash << 10;
|
|
hash ^= hash >> 6;
|
|
hash += uint32_t(uintptr_t(result)) + 0x68843823;
|
|
hash += hash << 10;
|
|
hash ^= hash >> 6;
|
|
hash += uint32_t(size) + 0x81444120;
|
|
hash += hash << 10;
|
|
hash ^= hash >> 6;
|
|
return result;
|
|
}
|
|
void free(void *p) {
|
|
hash += uint32_t(uintptr_t(p)) + 0x87823448;
|
|
dlfree(p);
|
|
}
|
|
int memhash() {
|
|
return (hash & 0x3FFFFFFF) | 0x40000000;
|
|
}
|
|
} // namespace eng
|
|
|
|
#endif // ifdef __linux__
|
|
|
|
|