193 lines
5.4 KiB
C
193 lines
5.4 KiB
C
/*----------------------------------------------------------
|
|
* HTBLA-Leonding
|
|
* ---------------------------------------------------------
|
|
* Title: Simple Memory Manager.
|
|
* Author: Marc Tismonar
|
|
* ----------------------------------------------------------
|
|
* Description:
|
|
* Implementation of a simple memory manager.
|
|
* ----------------------------------------------------------
|
|
*/
|
|
|
|
#include "mem_man.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/**
|
|
* The memory manager operates on a global, statically allocated, linear memory partition (array).
|
|
* This memory is organized in memory blocks of 32 bits (4 byte), the number of totally
|
|
* available blocks is defined by the constant 'MEMORY_BLOCK_CNT'.
|
|
* The smallest allocatable memory unit is one block, larger memory units are allocates always
|
|
* a multiple of one block. This means, if a memory up to 32 bit is requested, one block is allocated,
|
|
* if a memory of size from 33 bits to 64 bits is request, two blocks are allocated, and so one.
|
|
*
|
|
* Each memory block shall be initialized with the pattern '0xDEADBEEF", freed memory shall be set to
|
|
* the pattern '0xAFFEBAFF'. Such regions are easily recognizable in a memory dump.
|
|
*
|
|
* The housekeeping data (start address and size) of allocated memory units
|
|
* shall be maintained in a linked list.
|
|
*/
|
|
|
|
#define MEMORY_BLOCK_CNT 1024
|
|
#define BYTES_PER_BLOCK 4
|
|
|
|
static int memory[MEMORY_BLOCK_CNT];
|
|
static size_t allocatedBlocks = 0;
|
|
static size_t freeBlocks = MEMORY_BLOCK_CNT;
|
|
|
|
static void init_memory() {
|
|
static int initialized = 0;
|
|
if (!initialized) {
|
|
for (size_t i = 0; i < MEMORY_BLOCK_CNT; i++) {
|
|
memory[i] = 0xAFFEBAFF;
|
|
}
|
|
initialized = 1;
|
|
}
|
|
}
|
|
|
|
void *my_alloc(size_t size) {
|
|
init_memory();
|
|
|
|
if (size == 0) {
|
|
return (void*)0;
|
|
}
|
|
|
|
size_t i = 0;
|
|
size_t start = MEMORY_BLOCK_CNT;
|
|
size_t freePlaces = 0;
|
|
size_t blocks_needed = (size + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
|
|
|
while (i < MEMORY_BLOCK_CNT) {
|
|
if (memory[i] == 0xAFFEBAFF) {
|
|
if (freePlaces == 0) {
|
|
start = i;
|
|
}
|
|
freePlaces++;
|
|
|
|
if (freePlaces == blocks_needed) {
|
|
for (size_t j = 0; j < blocks_needed; j++) {
|
|
memory[start + j] = 0xDEADBEEF;
|
|
}
|
|
freeBlocks -= blocks_needed;
|
|
allocatedBlocks += blocks_needed;
|
|
return &memory[start];
|
|
}
|
|
} else {
|
|
freePlaces = 0;
|
|
start = MEMORY_BLOCK_CNT;
|
|
}
|
|
i++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void my_free(void *p) {
|
|
int start = get_unit_index(p);
|
|
if (start == -1) {
|
|
printf("Memory is not allocated\n");
|
|
return;
|
|
}
|
|
|
|
size_t freed_blocks = 0;
|
|
size_t i = start;
|
|
|
|
while (i < MEMORY_BLOCK_CNT && memory[i] == 0xDEADBEEF) {
|
|
memory[i] = 0xAFFEBAFF;
|
|
freed_blocks++;
|
|
i++;
|
|
}
|
|
|
|
freeBlocks += freed_blocks;
|
|
allocatedBlocks -= freed_blocks;
|
|
}
|
|
|
|
MemStat mem_get_statistics() {
|
|
init_memory();
|
|
|
|
MemStat stat;
|
|
stat.total_bytes = MEMORY_BLOCK_CNT * BYTES_PER_BLOCK;
|
|
stat.free_bytes = freeBlocks * BYTES_PER_BLOCK;
|
|
stat.used_bytes = allocatedBlocks * BYTES_PER_BLOCK;
|
|
stat.free_percentage = (double)stat.free_bytes / (double)stat.total_bytes * 100;
|
|
|
|
size_t units_count = 0;
|
|
size_t i = 0;
|
|
|
|
while (i < MEMORY_BLOCK_CNT) {
|
|
if (memory[i] == 0xDEADBEEF) {
|
|
units_count++;
|
|
while (i < MEMORY_BLOCK_CNT && memory[i] == 0xDEADBEEF) {
|
|
i++;
|
|
}
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
stat.allocated_units_count = units_count;
|
|
|
|
size_t largest_free_unit = 0;
|
|
size_t current_free_unit = 0;
|
|
|
|
for (i = 0; i < MEMORY_BLOCK_CNT; i++) {
|
|
if (memory[i] == 0xAFFEBAFF) {
|
|
current_free_unit++;
|
|
} else {
|
|
if (current_free_unit > largest_free_unit) {
|
|
largest_free_unit = current_free_unit;
|
|
}
|
|
current_free_unit = 0;
|
|
}
|
|
}
|
|
|
|
if (current_free_unit > largest_free_unit) {
|
|
largest_free_unit = current_free_unit;
|
|
}
|
|
|
|
stat.larger_free_unit_bytes = largest_free_unit * BYTES_PER_BLOCK;
|
|
return stat;
|
|
}
|
|
|
|
void mem_print_units() {
|
|
init_memory();
|
|
|
|
size_t i = 0;
|
|
while (i < MEMORY_BLOCK_CNT) {
|
|
if (memory[i] == 0xDEADBEEF) {
|
|
size_t start = i;
|
|
size_t size = 0;
|
|
while (i < MEMORY_BLOCK_CNT && memory[i] == 0xDEADBEEF) {
|
|
size++;
|
|
i++;
|
|
}
|
|
printf("Allocated: Index %zu; Size: %zu\n", start, size);
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int get_unit_index(void *p_mem) {
|
|
if (p_mem < (void*)memory || p_mem >= (void*)(memory + MEMORY_BLOCK_CNT)) {
|
|
return -1;
|
|
}
|
|
|
|
int index = ((int*)p_mem - memory);
|
|
|
|
if (memory[index] != 0xDEADBEEF) {
|
|
return -1;
|
|
}
|
|
|
|
while (index > 0 && memory[index-1] == 0xDEADBEEF) {
|
|
index--;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
void mem_dump() {
|
|
init_memory();
|
|
|
|
for (size_t i = 0; i < MEMORY_BLOCK_CNT; i++) {
|
|
printf("Memory: Index %zu; Content 0x%X\n", i, memory[i]);
|
|
}
|
|
}
|