/* ==========================================================================
* libarena/src/proto.c - Custom Memory Allocator Interface
* --------------------------------------------------------------------------
* Copyright (c) 2006 William Ahern
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
* ==========================================================================
*/
#include <stdlib.h> /* size_t malloc(3) realloc(3) free(3) */
#include <stddef.h> /* offsetof() */
#include <string.h> /* strerror(3) memmove(3) */
#include <errno.h> /* ENOMEM errno */
#include "align.h"
#include "proto.h" /* struct arena_prototype */
#include "rbits.h"
#ifndef MIN
#define MIN(a, b) (((a) < (b))? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b))? (a) : (b))
#endif
/*
* ARENA_SYSTEM_ALIGNMENT is the lowest common alignment denominator for all
* datatypes. However, the system malloc implementation may align even
* stricter. For instance, OpenBSD's malloc aligns on 16 byte boundaries on
* all implementations, even though most only strictly require an 8 byte
* boundary.
*/
#ifndef ARENA_SYSTEM_MALLOC_ALIGNS
#define ARENA_SYSTEM_MALLOC_ALIGNS ARENA_SYSTEM_ALIGNMENT
#endif
const char *ARENA_NOERROR = "Success";
static int sys_errno;
static void *sys_malloc(const struct arena_prototype *sys, size_t size, size_t align) {
unsigned char *p;
size_t ptroff;
if (align == 0)
align = ARENA_SYSTEM_ALIGNMENT;
ptroff = rbits_ptroffset((unsigned char *)ARENA_SYSTEM_MALLOC_ALIGNS,size,align);
if (!(p = malloc(ptroff + size)))
sys_errno = errno;
(void)rbits_put(p,ptroff,size,0);
return p + ptroff;
} /* sys_malloc() */
static void *sys_realloc(const struct arena_prototype *sys, void *q, size_t dstlen, size_t align) {
unsigned char *p;
size_t srcoff, dstoff, srclen;
if (align == 0)
align = ARENA_SYSTEM_ALIGNMENT;
if (q) {
srclen = rbits_get((unsigned char *)q - 1,&p);
srcoff = (unsigned char *)q - p;
p = (unsigned char *)q - srcoff;
} else {
srclen = 0;
srcoff = 0;
p = q;
}
if (dstlen == 0) {
free(p);
return 0;
}
dstoff = MAX(srcoff,rbits_ptroffset((unsigned char *)ARENA_SYSTEM_MALLOC_ALIGNS,dstlen,align));
if (!(p = realloc(p,dstoff + dstlen))) {
sys_errno = errno;
return 0;
}
/* Do we need to shift the contents to write out the new size? */
if (dstoff > srcoff) {
(void)memmove(p + dstoff,p + srcoff,MIN(srclen,dstlen));
}
(void)rbits_put(p,dstoff,dstlen,0);
return p + dstoff;
} /* sys_realloc() */
static void sys_free(const struct arena_prototype *sys, void *q) {
unsigned char *p;
if (q == 0)
return /* void */;
(void)rbits_get((unsigned char *)q - 1,&p);
free(p);
return /* void */;
} /* sys_free() */
static const char sys_name[] = "stdlib + alignment";
static const char *sys_instanceof(const struct arena_prototype *sys) {
return &sys_name[0];
} /* sys_instanceof() */
static const char *sys_strerror(const struct arena_prototype *sys) {
if (sys_errno)
return strerror(sys_errno);
return ARENA_NOERROR;
} /* sys_strerror() */
static void sys_clearerr(const struct arena_prototype *sys) {
sys_errno = 0;
} /* sys_clearerr() */
static const struct arena_prototype arena_stdlib_aligned = {
/* .malloc = */ sys_malloc,
/* .realloc = */ sys_realloc,
/* .free = */ sys_free,
/* .instanceof = */ sys_instanceof,
/* .strerror = */ sys_strerror,
/* .clearerr = */ sys_clearerr,
};
const struct arena_prototype *ARENA_STDLIB_ALIGNED = &arena_stdlib_aligned;
static int null_errno;
static void *null_malloc(const struct arena_prototype *null, size_t size, size_t align) {
void *p;
if (!(p = malloc(size)))
return null_errno = errno, (void *)0;
#if 0 /* If we can't do it for null_realloc, may as well not do it here. */
if (0 != ((uintptr_t)p % align))
return free(p), null_errno = errno, (void *)0;
#endif
return p;
} /* null_malloc() */
static void *null_realloc(const struct arena_prototype *null, void *p, size_t size, size_t align) {
if (!(p = realloc(p, size)))
return null_errno = errno, (void *)0;
return p;
} /* null_realloc() */
static void null_free(const struct arena_prototype *null, void *p) {
free(p);
return /* void */;
} /* null_free() */
static const char null_name[] = "null";
static const char *null_instanceof(const struct arena_prototype *null) {
return &null_name[0];
} /* null_instanceof() */
static const char *null_strerror(const struct arena_prototype *null) {
if (null_errno)
return strerror(null_errno);
return ARENA_NOERROR;
} /* null_strerror() */
static void null_clearerr(const struct arena_prototype *null) {
null_errno = 0;
} /* null_clearerr() */
static const struct arena_prototype arena_stdlib = {
/* .malloc = */ null_malloc,
/* .realloc = */ null_realloc,
/* .free = */ null_free,
/* .instanceof = */ null_instanceof,
/* .strerror = */ null_strerror,
/* .clearerr = */ null_clearerr,
};
const struct arena_prototype *ARENA_STDLIB = &arena_stdlib;
int arena_debug(void) {
extern char *getenv(const char *);
static int debug = 0;
if (!debug)
debug = (getenv("ARENA_DEBUG"))? 1 : -1;
return (debug > 0)? 1 : 0;
} /* arena_debug() */
syntax highlighted by Code2HTML, v. 0.9.1