#define FATALERRORS 1
#ifdef INTERNAL_MALLOC
#include <stdlib.h>
#include "Xos.h"
#include "misc.h"
#include "X.h"
#ifdef XALLOC_LOG
#include <stdio.h>
#endif
extern Bool Must_have_memory;
#define XALLOC_DEBUG
#ifdef XALLOC_DEBUG
#define XFREE_ERASES
#endif
#define MAX_SMALL 264
#define MIN_LARGE (11*1024)
#define SIZE_STEPS (sizeof(double))
#define SIZE_HEADER (2*sizeof(long))
#ifdef XALLOC_DEBUG
#if defined(__sparc__)
#define SIZE_TAIL (2*sizeof(long))
#else
#define SIZE_TAIL (sizeof(long))
#endif
#endif
#undef TAIL_SIZE
#ifdef SIZE_TAIL
#define TAIL_SIZE SIZE_TAIL
#else
#define TAIL_SIZE 0
#endif
#if defined (_LP64) || \
defined(__alpha__) || defined(__alpha) || \
defined(__ia64__) || defined(ia64) || \
defined(__sparc64__) || \
defined(__s390x__) || \
defined(__AMD64__) || defined(AMD64) || \
(defined(sgi) && _MIPS_SZLONG == 64))
#define MAGIC 0x1404196414071968
#define MAGIC_FREE 0x1506196615061966
#define MAGIC2 0x2515207525182079
#else
#define MAGIC 0x14071968
#define MAGIC_FREE 0x15061966
#define MAGIC2 0x25182079
#endif
#ifdef XALLOC_LOG
#define XALLOC_LOG_FILE "/tmp/Xalloc.log"
#define LOG_BODY(_body) \
{ FILE *f; \
f = fopen(XALLOC_LOG_FILE, "a"); \
if (NULL!=f) { \
_body; \
fclose(f); \
} \
}
#if defined(linux) && defined(i386)
#define LOG_ALLOC(_fun, _size, _ret) \
{ unsigned long *from; \
__asm__("movl %%ebp,%0" : "=r" (from) : ); \
LOG_BODY(fprintf(f, "%s\t%i\t%p\t[%lu]\n", _fun, _size, _ret, *(from+1))) \
}
#else
#define LOG_ALLOC(_fun, _size, _ret) \
LOG_BODY(fprintf(f, "%s\t%i\t%p\n", _fun, _size, _ret))
#endif
#define LOG_REALLOC(_fun, _ptr, _size, _ret) \
LOG_BODY(fprintf(f, "%s\t%p\t%i\t%p\n", _fun, _ptr, _size, _ret))
#define LOG_FREE(_fun, _ptr) \
LOG_BODY(fprintf(f, "%s\t%p\n", _fun, _ptr))
#else
#define LOG_ALLOC(_fun, _size, _ret)
#define LOG_REALLOC(_fun, _ptr, _size, _ret)
#define LOG_FREE(_fun, _ptr)
#endif
static unsigned long *free_lists[MAX_SMALL/SIZE_STEPS];
#if defined(linux)
#define HAS_MMAP_ANON
#include <sys/types.h>
#include <sys/mman.h>
#include <asm/page.h>
#define HAS_SC_PAGESIZE
#define HAS_GETPAGESIZE
#endif
#if defined(__GNU__)
#define HAS_MMAP_ANON
#include <sys/types.h>
#include <sys/mman.h>
#include <mach/vm_param.h>
#define HAS_SC_PAGESIZE
#define HAS_GETPAGESIZE
#endif
#if defined(CSRG_BASED)
#define HAS_MMAP_ANON
#define HAS_GETPAGESIZE
#include <sys/types.h>
#include <sys/mman.h>
#endif
#if defined(DGUX)
#define HAS_GETPAGESIZE
#define MMAP_DEV_ZERO
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
#if defined(SVR4) && !defined(DGUX)
#define MMAP_DEV_ZERO
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
#if defined(sun) && !defined(SVR4)
#define MMAP_DEV_ZERO
#define HAS_GETPAGESIZE
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef XNO_SYSCONF
#undef _SC_PAGESIZE
#endif
#if defined(HAS_MMAP_ANON) || defined (MMAP_DEV_ZERO)
static int pagesize;
#endif
#ifdef MMAP_DEV_ZERO
static int devzerofd = -1;
#include <errno.h>
#endif
void XfreeTrap(void)
{
}
void *
Xalloc (unsigned long amount)
{
register unsigned long *ptr;
int indx;
if (amount == 0) {
LOG_ALLOC("Xalloc=0", amount, 0);
return NULL;
}
if ((long)amount < 0) {
#ifdef FATALERRORS
FatalError("Xalloc: Xalloc(<0)\n");
#else
ErrorF("Xalloc warning: Xalloc(<0) ignored..\n");
#endif
LOG_ALLOC("Xalloc<0", amount, 0);
return NULL;
}
#if defined(__alpha__) || defined(__alpha) || \
defined(__sparc__) || \
defined(__mips__) || \
defined(__powerpc__) || \
defined(__arm32__) || \
defined(__ia64__) || defined(ia64) || \
defined(__s390x__) || defined(__s390__)
amount = (amount + (sizeof(long)-1)) & ~(sizeof(long)-1);
#endif
if (amount <= MAX_SMALL) {
indx = (amount-1) / SIZE_STEPS;
ptr = free_lists[indx];
if (NULL == ptr) {
amount = (indx+1) * SIZE_STEPS;
ptr = (unsigned long *)calloc(1,(amount+SIZE_HEADER+TAIL_SIZE)
* (amount<100 ? 40 : 20));
if (NULL!=ptr) {
int i;
unsigned long *p1, *p2;
p1 = 0;
p2 = (unsigned long *)((char *)ptr + SIZE_HEADER);
for (i=0; i<(amount<100 ? 40 : 20); i++) {
p1 = p2;
p1[-2] = amount;
#ifdef XALLOC_DEBUG
p1[-1] = MAGIC_FREE;
#endif
#ifdef SIZE_TAIL
*(unsigned long *)((unsigned char *)p1 + amount) = MAGIC2;
#endif
p2 = (unsigned long *)((char *)p1 + SIZE_HEADER + amount + TAIL_SIZE);
*(unsigned long **)p1 = p2;
}
*(unsigned long **)p1 = NULL;
free_lists[indx] = (unsigned long *)((char *)ptr + SIZE_HEADER + amount + TAIL_SIZE + SIZE_HEADER);
ptr = (unsigned long *)((char *)ptr + SIZE_HEADER);
LOG_ALLOC("Xalloc-S", amount, ptr);
ptr[-1] = MAGIC;
return (void *)ptr;
}
} else {
free_lists[indx] = *((unsigned long **)ptr);
#ifdef XALLOC_DEBUG
ptr[-1] = MAGIC;
#endif
LOG_ALLOC("Xalloc-S", amount, ptr);
return (void *)ptr;
}
#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
} else if (amount >= MIN_LARGE) {
amount += SIZE_HEADER + TAIL_SIZE;
amount = (amount + pagesize-1) & ~(pagesize-1);
#ifdef MMAP_DEV_ZERO
ptr = (unsigned long *)mmap((caddr_t)0,
(size_t)amount,
PROT_READ | PROT_WRITE,
MAP_PRIVATE,
devzerofd,
(off_t)0);
#else
ptr = (unsigned long *)mmap((caddr_t)0,
(size_t)amount,
PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE,
-1,
(off_t)0);
#endif
if (-1!=(long)ptr) {
ptr[0] = amount - SIZE_HEADER - TAIL_SIZE;
#ifdef XALLOC_DEBUG
ptr[1] = MAGIC;
#endif
#ifdef SIZE_TAIL
((unsigned long *)((char *)ptr + amount - TAIL_SIZE))[0] = MAGIC2;
#endif
ptr = (unsigned long *)((char *)ptr + SIZE_HEADER);
LOG_ALLOC("Xalloc-L", amount, ptr);
return (void *)ptr;
}
#endif
} else {
ptr=(unsigned long *)calloc(1,amount+SIZE_HEADER+TAIL_SIZE);
if (ptr != (unsigned long *)NULL) {
ptr[0] = amount;
#ifdef XALLOC_DEBUG
ptr[1] = MAGIC;
#endif
#ifdef SIZE_TAIL
*(unsigned long *)((char *)ptr + amount + SIZE_HEADER) = MAGIC2;
#endif
ptr = (unsigned long *)((char *)ptr + SIZE_HEADER);
LOG_ALLOC("Xalloc-M", amount, ptr);
return (void *)ptr;
}
}
if (Must_have_memory)
FatalError("Out of memory");
LOG_ALLOC("Xalloc-oom", amount, 0);
return NULL;
}
pointer
XNFalloc (unsigned long amount)
{
register pointer ptr;
if (amount == 0) {
LOG_ALLOC("XNFalloc=0", amount, 0);
return NULL;
}
if ((long)amount < 0) {
#ifdef FATALERRORS
FatalError("Xalloc: XNFalloc(<0)\n");
#else
ErrorF("Xalloc warning: XNFalloc(<0) ignored..\n");
#endif
LOG_ALLOC("XNFalloc<0", amount, 0);
return (unsigned long *)NULL;
}
ptr = Xalloc(amount);
if (!ptr)
{
FatalError("Out of memory");
}
return ptr;
}
pointer
Xcalloc (unsigned long amount)
{
pointer ret;
ret = Xalloc (amount);
if (ret != 0
#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
&& (amount < MIN_LARGE)
#endif
)
bzero ((char *) ret, (int) amount);
return ret;
}
void *
XNFcalloc (unsigned long amount)
{
pointer ret;
ret = XNFalloc (amount);
if (ret != 0
#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
&& (amount < MIN_LARGE)
#endif
)
bzero ((char *) ret, (int) amount);
return ret;
}
void *
Xrealloc (pointer ptr, unsigned long amount)
{
register unsigned long *new_ptr;
if (amount == 0) {
if (ptr)
Xfree(ptr);
LOG_REALLOC("Xrealloc=0", ptr, amount, 0);
return NULL;
}
if ((long)amount < 0) {
#ifdef FATALERRORS
FatalError("Xalloc: Xrealloc(<0)\n");
#else
ErrorF("Xalloc warning: Xrealloc(<0) ignored..\n");
#endif
if (ptr)
Xfree(ptr);
LOG_REALLOC("Xrealloc<0", ptr, amount, 0);
return NULL;
}
new_ptr = Xalloc(amount);
if ( (new_ptr) && (ptr) ) {
unsigned long old_size;
old_size = ((unsigned long *)ptr)[-2];
#ifdef XALLOC_DEBUG
if (MAGIC != ((unsigned long *)ptr)[-1]) {
if (MAGIC_FREE == ((unsigned long *)ptr)[-1]) {
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: range already freed in Xrealloc() :-(\n");
#else
ErrorF("Xalloc error: range already freed in Xrealloc() :-(\a\n");
sleep(5);
XfreeTrap();
#endif
LOG_REALLOC("Xalloc error: ranged already freed in Xrealloc() :-(",
ptr, amount, 0);
return NULL;
}
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: header corrupt in Xrealloc() :-(\n");
#else
ErrorF("Xalloc error: header corrupt in Xrealloc() :-(\n");
XfreeTrap();
#endif
LOG_REALLOC("Xalloc error: header corrupt in Xrealloc() :-(",
ptr, amount, 0);
return NULL;
}
#endif
memcpy((char *)new_ptr, (char *)ptr, (amount < old_size ? amount : old_size));
}
if (ptr)
Xfree(ptr);
if (new_ptr) {
LOG_REALLOC("Xrealloc", ptr, amount, new_ptr);
return (void *)new_ptr;
}
if (Must_have_memory)
FatalError("Out of memory");
LOG_REALLOC("Xrealloc", ptr, amount, 0);
return NULL;
}
void *
XNFrealloc (pointer ptr, unsigned long amount)
{
if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL)
{
FatalError( "Out of memory" );
}
return ptr;
}
void
Xfree(pointer ptr)
{
unsigned long size;
unsigned long *pheader;
if (!ptr)
return;
pheader = (unsigned long *)((char *)ptr - SIZE_HEADER);
#ifdef XALLOC_DEBUG
if (MAGIC != pheader[1]) {
if (MAGIC_FREE == pheader[1]) {
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: range already freed in Xrealloc() :-(\n");
#else
ErrorF("Xalloc error: range already freed in Xrealloc() :-(\a\n");
sleep(5);
XfreeTrap();
#endif
LOG_FREE("Xalloc error: ranged already freed in Xrealloc() :-(", ptr);
return;
}
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: Header corrupt in Xfree() :-(\n");
#else
ErrorF("Xalloc error: Header corrupt in Xfree() :-(\n");
XfreeTrap();
#endif
LOG_FREE("Xalloc error: Header corrupt in Xfree() :-(", ptr);
return;
}
#endif
size = pheader[0];
if (size <= MAX_SMALL) {
int indx;
#ifdef SIZE_TAIL
if (MAGIC2 != *(unsigned long *)((char *)ptr + size)) {
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: Tail corrupt in Xfree() for small block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
#else
ErrorF("Xalloc error: Tail corrupt in Xfree() for small block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
XfreeTrap();
#endif
LOG_FREE("Xalloc error: Tail corrupt in Xfree() for small block", ptr);
return;
}
#endif
#ifdef XFREE_ERASES
memset(ptr,0xF0,size);
#endif
#ifdef XALLOC_DEBUG
pheader[1] = MAGIC_FREE;
#endif
indx = (size-1) / SIZE_STEPS;
*(unsigned long **)(ptr) = free_lists[indx];
free_lists[indx] = (unsigned long *)ptr;
LOG_FREE("Xfree", ptr);
return;
#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
} else if (size >= MIN_LARGE) {
#ifdef SIZE_TAIL
if (MAGIC2 != ((unsigned long *)((char *)ptr + size))[0]) {
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: Tail corrupt in Xfree() for big block (adr=0x%x, val=0x%x)\n",(char *)ptr+size,((unsigned long *)((char *)ptr + size))[0]);
#else
ErrorF("Xalloc error: Tail corrupt in Xfree() for big block (adr=0x%x, val=0x%x)\n",(char *)ptr+size,((unsigned long *)((char *)ptr + size))[0]);
XfreeTrap();
#endif
LOG_FREE("Xalloc error: Tail corrupt in Xfree() for big block", ptr);
return;
}
size += SIZE_TAIL;
#endif
LOG_FREE("Xfree", ptr);
size += SIZE_HEADER;
munmap((caddr_t)pheader, (size_t)size);
#endif
} else {
#ifdef SIZE_TAIL
if (MAGIC2 != *(unsigned long *)((char *)ptr + size)) {
#ifdef FATALERRORS
XfreeTrap();
FatalError("Xalloc error: Tail corrupt in Xfree() for medium block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
#else
ErrorF("Xalloc error: Tail corrupt in Xfree() for medium block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
XfreeTrap();
#endif
LOG_FREE("Xalloc error: Tail corrupt in Xfree() for medium block", ptr);
return;
}
#endif
#ifdef XFREE_ERASES
memset(pheader,0xF0,size+SIZE_HEADER);
#endif
#ifdef XALLOC_DEBUG
pheader[1] = MAGIC_FREE;
#endif
LOG_FREE("Xfree", ptr);
free((char *)pheader);
}
}
void
OsInitAllocator (void)
{
static Bool beenhere = FALSE;
if (beenhere)
return;
beenhere = TRUE;
#if defined(HAS_MMAP_ANON) || defined (MMAP_DEV_ZERO)
pagesize = -1;
#if defined(_SC_PAGESIZE) || defined(HAS_SC_PAGESIZE)
pagesize = sysconf(_SC_PAGESIZE);
#endif
#ifdef _SC_PAGE_SIZE
if (pagesize == -1)
pagesize = sysconf(_SC_PAGE_SIZE);
#endif
#ifdef HAS_GETPAGESIZE
if (pagesize == -1)
pagesize = getpagesize();
#endif
#ifdef PAGE_SIZE
if (pagesize == -1)
pagesize = PAGE_SIZE;
#endif
if (pagesize == -1)
FatalError("OsInitAllocator: Cannot determine page size\n");
#endif
bzero ((char *) free_lists, MAX_SMALL/SIZE_STEPS*sizeof(unsigned long *));
#ifdef MMAP_DEV_ZERO
if (devzerofd < 0) {
if ((devzerofd = open("/dev/zero", O_RDWR, 0)) < 0)
FatalError("OsInitAllocator: Cannot open /dev/zero (errno=%d)\n",
errno);
}
#endif
#ifdef XALLOC_LOG
{
FILE *f;
f = fopen(XALLOC_LOG_FILE, "w");
if (NULL!=f)
fclose(f);
}
#endif
}
#else
static int no_internal_xalloc;
#endif