Files
2025-04-25 16:32:38 +01:00

395 lines
7.3 KiB
C

/*
* Copyright (c) 2011 Bharath Ramesh <bramesh.dev@gmail.com>
*
* Distributed under the terms of GNU LGPL, version 2.1
*/
#include <stdint.h>
#include <string.h>
// #include "brmalloc.h"
// ------------
// User defined
#define MIN_ALLOC_SIZE ((size_t)8U)
#define MAX_ALLOC_SIZE ((size_t)4096U)
#define MAX_NUM_ALLOCS 8192
#define NUM_ITERATIONS 32UNIMPLEMENTED
// ------------
#define BITS_PER_LONG 64
#define LOG_BITS_PER_BYTE 3
#define LOG_BITS_PER_LONG 6
#define LOG_BYTES_PER_LONG 3
#define MAX_LONG 0xffffffffffffffff
#define K ((size_t)1024U)
#define M ((size_t)1024U * K)
#define G ((size_t)1024U * M)
#define MALLOC_OVERHEAD ((size_t)16U)
#ifndef ABORT
#define ABORT() abort()
#endif
#ifndef EXIT_ERR
#define EXIT_ERR() exit(EXIT_FAILURE)
#endif
#ifndef DEBUG
#include <stdio.h>
#define DEBUG(fmt, args...) printf("%d, %s: " fmt, __LINE__, __FUNCTION__, ##args)
#endif
#ifndef MALLOC_QUANTA
#define MALLOC_QUANTA ((size_t)16U)
#endif
#ifndef MALLOC_THRESHOLD
#define MALLOC_THRESHOLD ((size_t)1U * M)
#endif
#ifndef MALLOC_ZONE_SIZE
#define MALLOC_ZONE_SIZE ((size_t)16U * M)
#endif
#ifndef MMAP
#include <sys/mman.h>
#define MMAP_FLAGS (MAP_ANONYMOUS | MAP_PRIVATE)
#define MMAP_PROT (PROT_READ | PROT_WRITE)
#define MMAP(s) mmap (0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
#define MUNMAP(a, s) munmap ((a), (s))
#endif
struct __malloc_zone_type {
unsigned char *bmap;
size_t bmap_longs;
size_t free_size;
uint64_t id;
void *region;
uint64_t start_byte;
struct __malloc_zone_type *next;
};
typedef struct __malloc_zone_type malloc_zone_t;
static malloc_zone_t *mz_head = NULL, *mz_tail = NULL;
static uint8_t mqbits = 0;
static inline void
free_region (malloc_zone_t *mz, uint64_t loc, size_t nbytes)
{
unsigned char *bmap;
size_t bmap_longs;
uint64_t i, i_b, j_b, lbits, nbits, pattern, *wordptr;
lbits = nbits = nbytes >> mqbits;
i_b = loc >> LOG_BITS_PER_LONG;
j_b = loc - (i_b << LOG_BITS_PER_LONG);
bmap = mz->bmap;
bmap_longs = mz->bmap_longs;
for (i = i_b; i < bmap_longs; ++i) {
if (lbits == 0)
break;
wordptr = (uint64_t *) bmap + i;
if (i == i_b) {
if ((j_b + nbits) < BITS_PER_LONG) {
pattern = ((uint64_t) 1 << nbits) - 1;
pattern = ~(pattern << j_b);
*wordptr &= pattern;
return;
}
pattern = ~(MAX_LONG << j_b);
*wordptr &= pattern;
lbits -= (BITS_PER_LONG -j_b);
continue;
}
if (lbits >= BITS_PER_LONG) {
*wordptr = 0;
lbits -= BITS_PER_LONG;
continue;
}
pattern = ~(((uint64_t) 1 << lbits) - 1);
*wordptr &= pattern;
return;
}
return;
}
static inline uint64_t
get_region (malloc_zone_t *mz, size_t nbytes)
{
unsigned char *bmap;
size_t bmap_longs;
uint64_t i = 0, i_b, j, j_b, l, nbits, rbits, pattern, word, *wordptr;
int64_t loc = -1;
nbits = rbits = nbytes >> mqbits;
bmap = mz->bmap;
bmap_longs = mz->bmap_longs;
l = mz->start_byte;
while (i < bmap_longs) {
if (rbits == 0)
break;
word = *((uint64_t *) bmap + l);
if (word == MAX_LONG) {
loc = -1;
rbits = nbits;
++i;
++l;
if (l == bmap_longs)
l = 0;
continue;
}
if (word == 0) {
if (rbits >= BITS_PER_LONG) {
rbits -= BITS_PER_LONG;
if (loc == -1)
loc = l << LOG_BITS_PER_LONG;
++i;
++l;
if (l == bmap_longs) {
l = 0;
loc = -1;
rbits = nbits;
}
continue;
}
rbits = 0;
if (loc == -1)
loc = l << LOG_BITS_PER_LONG;
break;
}
if (rbits >= BITS_PER_LONG) {
loc = -1;
rbits = nbits;
++i;
++l;
if (l == bmap_longs)
l = 0;
continue;
}
for (j = 0; j < BITS_PER_LONG; ++j) {
if (rbits == 0)
break;
if ((word >> j) & 1) {
loc = -1;
rbits = nbits;
++i;
++l;
if (l == bmap_longs)
l = 0;
break;
}
--rbits;
if (loc == -1)
loc = (l << LOG_BITS_PER_LONG) + j;
}
}
if ((rbits != 0) || (loc == -1))
return -1;
mz->start_byte = (loc + nbits) >> LOG_BITS_PER_LONG;
i_b = loc >> LOG_BITS_PER_LONG;
j_b = loc - (i_b << LOG_BITS_PER_LONG);
rbits = nbits;
for (i = i_b; i < bmap_longs; ++i) {
if (rbits == 0)
break;
wordptr = (uint64_t *) bmap + i;
if (i == i_b) {
if ((j_b + nbits) < BITS_PER_LONG) {
pattern = ((uint64_t) 1 << nbits) - 1;
pattern = pattern << j_b;
*wordptr |= pattern;
return loc;
}
pattern = MAX_LONG << j_b;
*wordptr |= pattern;
rbits -= (BITS_PER_LONG - j_b);
continue;
}
if (rbits >= BITS_PER_LONG) {
*wordptr = MAX_LONG;
rbits -= BITS_PER_LONG;
continue;
}
pattern = ((uint64_t) 1 << rbits) - 1;
*wordptr |= pattern;
return loc;
}
return loc;
}
static inline malloc_zone_t *
new_malloc_zone (void)
{
size_t bmap_size, bmap_longs;
malloc_zone_t *mz;
void *region;
region = MMAP (MALLOC_ZONE_SIZE);
if (region == MAP_FAILED) {
DEBUG ("ERROR: MMAP failed.\n");
return NULL;
}
bmap_size = (MALLOC_ZONE_SIZE / MALLOC_QUANTA) >> LOG_BITS_PER_BYTE;
bmap_longs = bmap_size >> LOG_BYTES_PER_LONG;
mz = (malloc_zone_t *) malloc (sizeof (malloc_zone_t));
mz->bmap = (unsigned char *) malloc (bmap_size);
if (mz->bmap == NULL) {
DEBUG ("ERROR: Unable to allocate bitmap.\n");
free (mz);
MUNMAP (region, MALLOC_ZONE_SIZE);
return NULL;
}
memset (mz->bmap, 0, bmap_size);
mz->bmap_longs = bmap_longs;
mz->free_size = MALLOC_ZONE_SIZE;
mz->id = (uint64_t) mz;
mz->region = region;
mz->start_byte = 0;
mz->next = NULL;
if (mz_tail != NULL)
mz_tail->next = mz;
mz_tail = mz;
if (mz_head == NULL)
mz_head = mz;
return mz;
}
static void __attribute__ ((constructor))
brm_init (void)
{
uint8_t i, no_ones;
size_t size;
no_ones = 0;
size = MALLOC_QUANTA;
for (i = 0; i < BITS_PER_LONG; ++i) {
if ((size >> i) & 1) {
++no_ones;
if (no_ones > 1) {
DEBUG ("ERROR: MALLOC_QUANTA not power of "
"2.\n");
EXIT_ERR ();
}
mqbits = i;
}
}
if (no_ones == 0) {
DEBUG ("ERROR: MALLOC_QUANTA set to 0 (zero).\n");
EXIT_ERR ();
}
if (new_malloc_zone () == NULL) {
DEBUG ("ERROR: new_malloc_zone failed.\n");
EXIT_ERR ();
}
return;
}
void
brm_free (void *ptr)
{
uint64_t *base;
malloc_zone_t *mz;
int64_t offset;
size_t size;
base = (uint64_t *) ptr - 2;
mz = (malloc_zone_t *) *((uint64_t *) base);
size = (size_t) *((uint64_t *) base + 1);
if (mz->id != (uint64_t) mz) {
DEBUG ("ptr: %p, base: %p\n", ptr, base);
DEBUG ("ERROR: data corruption.\n");
ABORT ();
}
offset = ((void *) base - mz->region) >> mqbits;
free_region (mz, offset, size);
mz->free_size += size;
return;
}
void *
brm_malloc (size_t size)
{
uint64_t addr;
malloc_zone_t *mz;
size_t nbytes;
int64_t offset;
if (size == 0)
return NULL;
nbytes = (size + MALLOC_OVERHEAD + MALLOC_QUANTA - 1) &
~(MALLOC_QUANTA - 1);
// printf(nbytes);
// if (nbytes >= MALLOC_THRESHOLD) {
// DEBUG ("UNIMPLEMENTED\n");
// EXIT_ERR();
// }
mz = mz_head;
while (1) {
if (nbytes > mz->free_size) {
DEBUG ("UNIMPLEMENTED\n");
EXIT_ERR ();
}
offset = get_region (mz, nbytes);
if (offset == -1) {
mz = mz->next;
if (mz == NULL) {
if ((mz = new_malloc_zone ()) == NULL) {
DEBUG ("ERROR: new_malloc zone "
"failed.\n");
EXIT_ERR ();
}
}
continue;
}
mz->free_size -= nbytes;
addr = (uint64_t) mz->region + ((size_t) offset << mqbits);
*((uint64_t *) addr) = (uint64_t) mz;
*((uint64_t *) addr + 1) = (uint64_t) nbytes;
break;
}
return (void *) (addr + 2 * sizeof (uint64_t));
}