2019-10-28 01:22:01 +03:00
|
|
|
#include "allocator.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
|
|
|
|
allocator *allocator_create(uint64_t blocks)
|
|
|
|
{
|
|
|
|
if (blocks >= 0x80000000 || blocks <= 1)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
uint64_t p2 = 1, total = 1;
|
|
|
|
while (p2 * 64 < blocks)
|
|
|
|
{
|
|
|
|
p2 = p2 * 64;
|
|
|
|
total += p2;
|
|
|
|
}
|
|
|
|
total -= p2;
|
|
|
|
total += (blocks+63) / 64;
|
|
|
|
allocator *buf = (allocator*)memalign(sizeof(uint64_t), (2 + total)*sizeof(uint64_t));
|
|
|
|
buf->size = blocks;
|
|
|
|
buf->last_one_mask = (blocks % 64) == 0
|
2019-11-08 00:19:17 +03:00
|
|
|
? UINT64_MAX
|
|
|
|
: ~(UINT64_MAX << (64 - blocks % 64));
|
2019-10-28 01:22:01 +03:00
|
|
|
for (uint64_t i = 0; i < blocks; i++)
|
|
|
|
{
|
|
|
|
buf->mask[i] = 0;
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void allocator_destroy(allocator *alloc)
|
|
|
|
{
|
|
|
|
free(alloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void allocator_set(allocator *alloc, uint64_t addr, bool value)
|
|
|
|
{
|
|
|
|
if (addr >= alloc->size)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uint64_t p2 = 1, offset = 0;
|
|
|
|
while (p2 * 64 < alloc->size)
|
|
|
|
{
|
|
|
|
offset += p2;
|
|
|
|
p2 = p2 * 64;
|
|
|
|
}
|
|
|
|
uint64_t cur_addr = addr;
|
|
|
|
bool is_last = true;
|
|
|
|
uint64_t value64 = value ? 1 : 0;
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
uint64_t last = offset + cur_addr/64;
|
|
|
|
uint64_t bit = cur_addr % 64;
|
|
|
|
if (((alloc->mask[last] >> bit) & 1) != value64)
|
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
alloc->mask[last] = alloc->mask[last] | (1 << bit);
|
|
|
|
if (alloc->mask[last] != (!is_last || cur_addr/64 < alloc->size/64
|
2019-11-08 00:19:17 +03:00
|
|
|
? UINT64_MAX : alloc->last_one_mask))
|
2019-10-28 01:22:01 +03:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
alloc->mask[last] = alloc->mask[last] & ~(1 << bit);
|
|
|
|
if (alloc->mask[last] != 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is_last = false;
|
|
|
|
if (p2 > 1)
|
|
|
|
{
|
|
|
|
p2 = p2 / 64;
|
|
|
|
offset -= p2;
|
|
|
|
cur_addr /= 64;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t allocator_find_free(allocator *alloc)
|
|
|
|
{
|
|
|
|
uint64_t p2 = 1, offset = 0, addr = 0, f, i;
|
|
|
|
while (p2 < alloc->size)
|
|
|
|
{
|
|
|
|
uint64_t mask = alloc->mask[offset + addr];
|
|
|
|
for (i = 0, f = 1; i < 64; i++, f <<= 1)
|
|
|
|
{
|
|
|
|
if (!(mask & f))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == 64)
|
|
|
|
{
|
|
|
|
// No space
|
2019-11-08 00:19:17 +03:00
|
|
|
return UINT64_MAX;
|
2019-10-28 01:22:01 +03:00
|
|
|
}
|
|
|
|
addr = (addr * 64) | i;
|
|
|
|
if (addr >= alloc->size)
|
|
|
|
{
|
|
|
|
// No space
|
2019-11-08 00:19:17 +03:00
|
|
|
return UINT64_MAX;
|
2019-10-28 01:22:01 +03:00
|
|
|
}
|
|
|
|
offset += p2;
|
|
|
|
p2 = p2 * 64;
|
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|