18
# define ALLOC_DEBUG_BLOCK_CHECK
22
#undef ALLOC_DEBUG_BLOCK_CHECK
25
#define CHAR_PTR(p) ((char *) (p))
26
#define PADD(p, a) (CHAR_PTR(p) + a)
27
#define PSUB(p1, p2) (CHAR_PTR(p1) - CHAR_PTR(p2))
31
#ifdef ALLOC_DEBUG_BLOCK_CHECK
34
xc_memsize_t size; /* reserved even after alloc */
35
xc_block_t *next; /* not used after alloc */
40
xc_memsize_t avail; /* total free */
41
xc_block_t headblock[1]; /* just as a pointer to first block*/
45
# include <linux/stddef.h>
46
# define XtOffsetOf(s_type, field) offsetof(s_type, field)
49
#define SizeOf(type, field) sizeof( ((type *) 0)->field )
50
#define BLOCK_HEADER_SIZE() (ALIGN( XtOffsetOf(xc_block_t, size) + SizeOf(xc_block_t, size) ))
52
#define BLOCK_MAGIC ((unsigned int) 0x87655678)
55
static inline void xc_block_setup(xc_block_t *b, xc_memsize_t size, xc_block_t *next) /* {{{ */
57
#ifdef ALLOC_DEBUG_BLOCK_CHECK
58
b->magic = BLOCK_MAGIC;
64
#ifdef ALLOC_DEBUG_BLOCK_CHECK
65
static void xc_block_check(xc_block_t *b) /* {{{ */
67
if (b->magic != BLOCK_MAGIC) {
68
fprintf(stderr, "0x%X != 0x%X magic wrong \n", b->magic, BLOCK_MAGIC);
73
# define xc_block_check(b) do { } while(0)
77
void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */
79
xc_block_t *prev, *cur;
81
xc_memsize_t realsize;
84
/* [xc_block_t:size|size] */
85
realsize = BLOCK_HEADER_SIZE() + size;
86
/* realsize is ALIGNed so next block start at ALIGNed address */
87
realsize = ALIGN(realsize);
90
fprintf(stderr, "avail: %d (%dKB). Allocate size: %d realsize: %d (%dKB)"
91
, mem->avail, mem->avail / 1024
93
, realsize, realsize / 1024
98
if (mem->avail < realsize) {
100
fprintf(stderr, " oom\n");
110
for (prev = mem->headblock; prev->next; prev = cur) {
111
/* while (prev->next != 0) { */
114
if (cur->size == realsize) {
115
/* found a perfect fit, stop searching */
119
/* make sure we can split on the block */
120
else if (cur->size > (sizeof(xc_block_t) + realsize) &&
121
cur->size < minsize) {
122
/* cur is acceptable and memller */
131
fprintf(stderr, " no fit chunk\n");
139
p = PADD(cur, BLOCK_HEADER_SIZE());
141
/* update the block header */
142
mem->avail -= realsize;
144
/* perfect fit, just unlink */
145
if (cur->size == realsize) {
146
prev->next = cur->next;
148
fprintf(stderr, " perfect fit. Got: %p\n", p);
153
/* make new free block after alloced space */
155
/* save, as it might be overwrited by newb (cur->size is ok) */
158
/* prev|cur |next=b */
160
newb = (xc_block_t *)PADD(cur, realsize);
161
xc_block_setup(newb, cur->size - realsize, b);
162
cur->size = realsize;
163
/* prev|cur|newb|next
168
fprintf(stderr, " -> avail: %d (%dKB). new next: %p offset: %d %dKB. Got: %p\n"
169
, mem->avail, mem->avail / 1024
171
, PSUB(newb, mem), PSUB(newb, mem) / 1024
176
/* prev|cur|newb|next
185
int xc_mem_free(xc_mem_t *mem, const void *p) /* {{{ return block size freed */
190
cur = (xc_block_t *) (CHAR_PTR(p) - BLOCK_HEADER_SIZE());
192
fprintf(stderr, "freeing: %p", p);
193
fprintf(stderr, ", size=%d", cur->size);
196
assert((char*)mem < (char*)cur && (char*)cur < (char*)mem + mem->size);
198
/* find free block right before the p */
200
while (b->next != 0 && b->next < cur) {
210
fprintf(stderr, ", avail %d (%dKB)", mem->avail, mem->avail / 1024);
214
/* combine prev|cur */
215
if (PADD(b, b->size) == (char *)cur) {
216
b->size += cur->size;
220
fprintf(stderr, ", combine prev");
224
/* combine cur|next */
226
if (PADD(cur, cur->size) == (char *)b) {
227
cur->size += b->size;
230
fprintf(stderr, ", combine next");
234
fprintf(stderr, " -> avail %d (%dKB)\n", mem->avail, mem->avail / 1024);
239
void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size) /* {{{ */
241
xc_memsize_t realsize = memb * size;
242
void *p = xc_mem_malloc(mem, realsize);
244
memset(p, 0, realsize);
248
void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size) /* {{{ */
250
void *newp = xc_mem_malloc(mem, size);
251
memcpy(newp, p, size);
256
char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len) /* {{{ */
258
void *p = xc_mem_malloc(mem, len + 1);
259
memcpy(p, str, len + 1);
263
char *xc_mem_strdup(xc_mem_t *mem, const char *str) /* {{{ */
265
return xc_mem_strndup(mem, str, strlen(str));
269
xc_memsize_t xc_mem_avail(xc_mem_t *mem) /* {{{ */
274
xc_memsize_t xc_mem_size(xc_mem_t *mem) /* {{{ */
280
const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem) /* {{{ */
282
return mem->headblock->next;
285
const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block) /* {{{ */
290
xc_memsize_t xc_mem_block_size(const xc_block_t *block) /* {{{ */
295
xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block) /* {{{ */
297
return ((char *) block) - ((char *) mem);
301
xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size) /* {{{ */
306
#define MINSIZE (ALIGN(sizeof(xc_mem_t)) + sizeof(xc_block_t))
307
/* requires at least the header and 1 tail block */
308
if (size < MINSIZE) {
309
fprintf(stderr, "xc_mem_init requires %d bytes at least\n", MINSIZE);
312
mem = (xc_mem_t *) ptr;
314
mem->avail = size - MINSIZE;
316
/* pointer to first block, right after ALIGNed header */
318
xc_block_setup(b, 0, (xc_block_t *) PADD(mem, ALIGN(sizeof(xc_mem_t))));
322
xc_block_setup(b, mem->avail, 0);
328
void xc_mem_destroy(xc_mem_t *mem) /* {{{ */
336
#define CHECK(a, msg) do { if ((a) == NULL) { puts(msg); return -1; } } while (0)
349
fprintf(stderr, "%s", "Input test size: ");
354
CHECK(memory = malloc(size), "OOM");
355
CHECK(ptrs = malloc(size * sizeof(void*)), "OOM");
356
CHECK(mem = xc_mem_init(memory, size), "Failed init memory allocator");
358
while ((p = xc_mem_malloc(mem, 1))) {
361
fprintf(stderr, "count=%d, random freeing\n", count);
364
i = (random() % count);
365
fprintf(stderr, "freeing %d: ", i);
366
xc_mem_free(mem, ptrs[i]);
367
ptrs[i] = ptrs[count - 1];