mm: implement heap with liballoc, might review later
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o \
|
OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o \
|
||||||
bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o \
|
bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o \
|
||||||
bin/keyboard.o bin/paging.o bin/page_alloc.o bin/page_tables.o \
|
bin/keyboard.o bin/paging.o bin/page_alloc.o bin/page_tables.o \
|
||||||
bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o bin/gdt.o bin/isr-asm.o
|
bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o bin/gdt.o bin/isr-asm.o bin/kheap.o bin/liballoc.o
|
||||||
|
|
||||||
# Define the compiler and assembler
|
# Define the compiler and assembler
|
||||||
#CC = i686-elf-gcc -D__is_katauos
|
#CC = i686-elf-gcc -D__is_katauos
|
||||||
@@ -124,6 +124,13 @@ bin/gdt.o: src/kernel/gdt.c
|
|||||||
bin/isr-asm.o: src/kernel/isr.asm
|
bin/isr-asm.o: src/kernel/isr.asm
|
||||||
$(AS) $(ASFLAGS) $< -o $@
|
$(AS) $(ASFLAGS) $< -o $@
|
||||||
|
|
||||||
|
bin/kheap.o: src/mm/kheap.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
bin/liballoc.o: src/mm/liballoc.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin/
|
rm -rf bin/
|
||||||
rm -f $(OUTPUT)
|
rm -f $(OUTPUT)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef KERNEL_HEAP_H
|
||||||
|
#define KERNEL_HEAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define KHEAP_START 0xE0000000 // Start of kernel heap
|
||||||
|
#define KHEAP_INITIAL_SIZE 0x100000 // 1 MiB initial size
|
||||||
|
#define KHEAP_END (KHEAP_START + KHEAP_INITIAL_SIZE)
|
||||||
|
#define KHEAP_PAGES (KHEAP_INITIAL_SIZE / PAGE_SIZE)
|
||||||
|
|
||||||
|
void kheap_init();
|
||||||
|
void* kvalloc(size_t npages);
|
||||||
|
void kvfree(void* addr, size_t npages);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#ifndef _LIBALLOC_H
|
||||||
|
#define _LIBALLOC_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// If we are told to not define our own size_t, then we
|
||||||
|
// skip the define.
|
||||||
|
#ifndef _ALLOC_SKIP_DEFINE
|
||||||
|
|
||||||
|
#ifndef _HAVE_SIZE_T
|
||||||
|
#define _HAVE_SIZE_T
|
||||||
|
typedef unsigned int size_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** This is a boundary tag which is prepended to the
|
||||||
|
* page or section of a page which we have allocated. It is
|
||||||
|
* used to identify valid memory blocks that the
|
||||||
|
* application is trying to free.
|
||||||
|
*/
|
||||||
|
struct boundary_tag
|
||||||
|
{
|
||||||
|
unsigned int magic; //< It's a kind of ...
|
||||||
|
unsigned int size; //< Requested size.
|
||||||
|
unsigned int real_size; //< Actual size.
|
||||||
|
int index; //< Location in the page table.
|
||||||
|
|
||||||
|
struct boundary_tag *split_left; //< Linked-list info for broken pages.
|
||||||
|
struct boundary_tag *split_right; //< The same.
|
||||||
|
|
||||||
|
struct boundary_tag *next; //< Linked list info.
|
||||||
|
struct boundary_tag *prev; //< Linked list info.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** This function is supposed to lock the memory data structures. It
|
||||||
|
* could be as simple as disabling interrupts or acquiring a spinlock.
|
||||||
|
* It's up to you to decide.
|
||||||
|
*
|
||||||
|
* \return 0 if the lock was acquired successfully. Anything else is
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
extern int liballoc_lock();
|
||||||
|
|
||||||
|
/** This function unlocks what was previously locked by the liballoc_lock
|
||||||
|
* function. If it disabled interrupts, it enables interrupts. If it
|
||||||
|
* had acquiried a spinlock, it releases the spinlock. etc.
|
||||||
|
*
|
||||||
|
* \return 0 if the lock was successfully released.
|
||||||
|
*/
|
||||||
|
extern int liballoc_unlock();
|
||||||
|
|
||||||
|
/** This is the hook into the local system which allocates pages. It
|
||||||
|
* accepts an integer parameter which is the number of pages
|
||||||
|
* required. The page size was set up in the liballoc_init function.
|
||||||
|
*
|
||||||
|
* \return NULL if the pages were not allocated.
|
||||||
|
* \return A pointer to the allocated memory.
|
||||||
|
*/
|
||||||
|
extern void* liballoc_alloc(int);
|
||||||
|
|
||||||
|
/** This frees previously allocated memory. The void* parameter passed
|
||||||
|
* to the function is the exact same value returned from a previous
|
||||||
|
* liballoc_alloc call.
|
||||||
|
*
|
||||||
|
* The integer value is the number of pages to free.
|
||||||
|
*
|
||||||
|
* \return 0 if the memory was successfully freed.
|
||||||
|
*/
|
||||||
|
extern int liballoc_free(void*,int);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *malloc(size_t); //< The standard function.
|
||||||
|
void *realloc(void *, size_t); //< The standard function.
|
||||||
|
void *calloc(size_t, size_t); //< The standard function.
|
||||||
|
void free(void *); //< The standard function.
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+4
-3
@@ -10,6 +10,7 @@
|
|||||||
#include "../include/fat.h"
|
#include "../include/fat.h"
|
||||||
#include "../include/task.h"
|
#include "../include/task.h"
|
||||||
#include "../include/multiboot.h"
|
#include "../include/multiboot.h"
|
||||||
|
#include "../include/liballoc.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -187,7 +188,7 @@ void kmain(unsigned int magic, unsigned int info)
|
|||||||
//heap_init();
|
//heap_init();
|
||||||
//printf("after heap_init\n");
|
//printf("after heap_init\n");
|
||||||
__asm__ __volatile__ ("sti");
|
__asm__ __volatile__ ("sti");
|
||||||
scheduler_init();
|
//scheduler_init();
|
||||||
printf("Kernel init sequence completed\n");
|
printf("Kernel init sequence completed\n");
|
||||||
|
|
||||||
char yooo[256] = "heheh";
|
char yooo[256] = "heheh";
|
||||||
@@ -204,8 +205,8 @@ void kmain(unsigned int magic, unsigned int info)
|
|||||||
char temp1[1024] = "rusya_krutoy";
|
char temp1[1024] = "rusya_krutoy";
|
||||||
char temp2[1024] = "katya_tozhe_krutaya";
|
char temp2[1024] = "katya_tozhe_krutaya";
|
||||||
|
|
||||||
huy = alloc_page();//heap_alloc(1024);
|
huy = malloc(64);//alloc_page();//heap_alloc(1024);
|
||||||
huy2 = alloc_page();//heap_alloc(1024);
|
huy2 = malloc(64);//alloc_page();//heap_alloc(1024);
|
||||||
|
|
||||||
memcpy(huy, temp1, sizeof(temp1));
|
memcpy(huy, temp1, sizeof(temp1));
|
||||||
memcpy(huy2, temp2, sizeof(temp1));
|
memcpy(huy2, temp2, sizeof(temp1));
|
||||||
|
|||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
// kernel_heap.c
|
||||||
|
#include "../include/kheap.h"
|
||||||
|
#include "../include/paging.h"
|
||||||
|
#include "../include/stdio.h"
|
||||||
|
#include "../include/string.h"
|
||||||
|
|
||||||
|
#include <liballoc.h>
|
||||||
|
|
||||||
|
int liballoc_lock() {
|
||||||
|
// Implement locking (disable interrupts or use spinlock)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int liballoc_unlock() {
|
||||||
|
// Implement unlocking
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* liballoc_alloc(int pages) {
|
||||||
|
return kvalloc(pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
int liballoc_free(void* ptr, int pages) {
|
||||||
|
kvfree(ptr, pages);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t kheap_bitmap[KHEAP_PAGES / 8];
|
||||||
|
|
||||||
|
// Test a bit in kernel heap bitmap
|
||||||
|
static int kheap_bitmap_test(uint32_t index) {
|
||||||
|
uint32_t byte = index / 8;
|
||||||
|
uint8_t bit = index % 8;
|
||||||
|
return (kheap_bitmap[byte] >> bit) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a bit in kernel heap bitmap
|
||||||
|
static void kheap_bitmap_set(uint32_t index) {
|
||||||
|
uint32_t byte = index / 8;
|
||||||
|
uint8_t bit = index % 8;
|
||||||
|
kheap_bitmap[byte] |= (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear a bit in kernel heap bitmap
|
||||||
|
static void kheap_bitmap_clear(uint32_t index) {
|
||||||
|
uint32_t byte = index / 8;
|
||||||
|
uint8_t bit = index % 8;
|
||||||
|
kheap_bitmap[byte] &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize kernel heap
|
||||||
|
void kheap_init() {
|
||||||
|
memset(kheap_bitmap, 0, sizeof(kheap_bitmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate contiguous virtual pages
|
||||||
|
void* kvalloc(size_t npages) {
|
||||||
|
// Limit allocation size for safety
|
||||||
|
if (npages > 1024 || npages == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t start = 0;
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
// Find contiguous free pages in bitmap
|
||||||
|
for (uint32_t i = 0; i < KHEAP_PAGES; i++) {
|
||||||
|
if (!kheap_bitmap_test(i)) {
|
||||||
|
count++;
|
||||||
|
if (count >= npages) {
|
||||||
|
start = i - npages + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < npages) {
|
||||||
|
return NULL; // Not enough contiguous space
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily store physical addresses
|
||||||
|
void* phys_addrs[npages];
|
||||||
|
uint32_t vaddr = KHEAP_START + start * PAGE_SIZE;
|
||||||
|
|
||||||
|
// Allocate physical pages first
|
||||||
|
for (uint32_t i = 0; i < npages; i++) {
|
||||||
|
phys_addrs[i] = alloc_page();
|
||||||
|
if (!phys_addrs[i]) {
|
||||||
|
// Cleanup on failure
|
||||||
|
for (uint32_t j = 0; j < i; j++) {
|
||||||
|
free_page(phys_addrs[j]);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark virtual pages as allocated
|
||||||
|
for (uint32_t i = start; i < start + npages; i++) {
|
||||||
|
kheap_bitmap_set(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map virtual to physical pages
|
||||||
|
for (uint32_t i = 0; i < npages; i++) {
|
||||||
|
map_page(phys_addrs[i], (void*)(vaddr + i * PAGE_SIZE),
|
||||||
|
PAGE_PRESENT | PAGE_RW);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free allocated pages
|
||||||
|
void kvfree(void* addr, size_t npages) {
|
||||||
|
uint32_t vaddr = (uint32_t)addr;
|
||||||
|
if (vaddr < KHEAP_START || vaddr >= KHEAP_END) {
|
||||||
|
printf("kvfree: invalid address 0x%x\n", vaddr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t start = (vaddr - KHEAP_START) / PAGE_SIZE;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < npages; i++) {
|
||||||
|
uint32_t current_vaddr = vaddr + i * PAGE_SIZE;
|
||||||
|
void* phys = get_physaddr((void*)current_vaddr);
|
||||||
|
|
||||||
|
if (phys) {
|
||||||
|
free_page(phys);
|
||||||
|
unmap_page((void*)current_vaddr);
|
||||||
|
} else {
|
||||||
|
printf("kvfree: no physical mapping for 0x%x\n", current_vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
kheap_bitmap_clear(start + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,533 @@
|
|||||||
|
#include <liballoc.h>
|
||||||
|
|
||||||
|
/** Durand's Ridiculously Amazing Super Duper Memory functions. */
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
#define LIBALLOC_MAGIC 0xc001c0de
|
||||||
|
#define MAXCOMPLETE 5
|
||||||
|
#define MAXEXP 32
|
||||||
|
#define MINEXP 8
|
||||||
|
|
||||||
|
#define MODE_BEST 0
|
||||||
|
#define MODE_INSTANT 1
|
||||||
|
|
||||||
|
#define MODE MODE_BEST
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct boundary_tag* l_freePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks
|
||||||
|
int l_completePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
unsigned int l_allocated = 0; //< The real amount of memory allocated.
|
||||||
|
unsigned int l_inuse = 0; //< The amount of memory in use (malloc'ed).
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static int l_initialized = 0; //< Flag to indicate initialization.
|
||||||
|
static int l_pageSize = 4096; //< Individual page size
|
||||||
|
static int l_pageCount = 16; //< Minimum number of pages to allocate.
|
||||||
|
|
||||||
|
|
||||||
|
// *********** HELPER FUNCTIONS *******************************
|
||||||
|
|
||||||
|
/** Returns the exponent required to manage 'size' amount of memory.
|
||||||
|
*
|
||||||
|
* Returns n where 2^n <= size < 2^(n+1)
|
||||||
|
*/
|
||||||
|
static inline int getexp( unsigned int size )
|
||||||
|
{
|
||||||
|
if ( size < (1<<MINEXP) )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("getexp returns -1 for %i less than MINEXP\n", size );
|
||||||
|
#endif
|
||||||
|
return -1; // Smaller than the quantum.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int shift = MINEXP;
|
||||||
|
|
||||||
|
while ( shift < MAXEXP )
|
||||||
|
{
|
||||||
|
if ( (1<<shift) > size ) break;
|
||||||
|
shift += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("getexp returns %i (%i bytes) for %i size\n", shift - 1, (1<<(shift -1)), size );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return shift - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void* liballoc_memset(void* s, int c, size_t n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for ( i = 0; i < n ; i++)
|
||||||
|
((char*)s)[i] = c;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
|
||||||
|
{
|
||||||
|
char *cdest;
|
||||||
|
char *csrc;
|
||||||
|
unsigned int *ldest = (unsigned int*)s1;
|
||||||
|
unsigned int *lsrc = (unsigned int*)s2;
|
||||||
|
|
||||||
|
while ( n >= sizeof(unsigned int) )
|
||||||
|
{
|
||||||
|
*ldest++ = *lsrc++;
|
||||||
|
n -= sizeof(unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdest = (char*)ldest;
|
||||||
|
csrc = (char*)lsrc;
|
||||||
|
|
||||||
|
while ( n > 0 )
|
||||||
|
{
|
||||||
|
*cdest++ = *csrc++;
|
||||||
|
n -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static void dump_array()
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
struct boundary_tag *tag = NULL;
|
||||||
|
|
||||||
|
printf("------ Free pages array ---------\n");
|
||||||
|
printf("System memory allocated: %i\n", l_allocated );
|
||||||
|
printf("Memory in used (malloc'ed): %i\n", l_inuse );
|
||||||
|
|
||||||
|
for ( i = 0; i < MAXEXP; i++ )
|
||||||
|
{
|
||||||
|
printf("%.2i(%i): ",i, l_completePages[i] );
|
||||||
|
|
||||||
|
tag = l_freePages[ i ];
|
||||||
|
while ( tag != NULL )
|
||||||
|
{
|
||||||
|
if ( tag->split_left != NULL ) printf("*");
|
||||||
|
printf("%i", tag->real_size );
|
||||||
|
if ( tag->split_right != NULL ) printf("*");
|
||||||
|
|
||||||
|
printf(" ");
|
||||||
|
tag = tag->next;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("'*' denotes a split to the left/right of a tag\n");
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static inline void insert_tag( struct boundary_tag *tag, int index )
|
||||||
|
{
|
||||||
|
int realIndex;
|
||||||
|
|
||||||
|
if ( index < 0 )
|
||||||
|
{
|
||||||
|
realIndex = getexp( tag->real_size - sizeof(struct boundary_tag) );
|
||||||
|
if ( realIndex < MINEXP ) realIndex = MINEXP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
realIndex = index;
|
||||||
|
|
||||||
|
tag->index = realIndex;
|
||||||
|
|
||||||
|
if ( l_freePages[ realIndex ] != NULL )
|
||||||
|
{
|
||||||
|
l_freePages[ realIndex ]->prev = tag;
|
||||||
|
tag->next = l_freePages[ realIndex ];
|
||||||
|
}
|
||||||
|
|
||||||
|
l_freePages[ realIndex ] = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void remove_tag( struct boundary_tag *tag )
|
||||||
|
{
|
||||||
|
if ( l_freePages[ tag->index ] == tag ) l_freePages[ tag->index ] = tag->next;
|
||||||
|
|
||||||
|
if ( tag->prev != NULL ) tag->prev->next = tag->next;
|
||||||
|
if ( tag->next != NULL ) tag->next->prev = tag->prev;
|
||||||
|
|
||||||
|
tag->next = NULL;
|
||||||
|
tag->prev = NULL;
|
||||||
|
tag->index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct boundary_tag* melt_left( struct boundary_tag *tag )
|
||||||
|
{
|
||||||
|
struct boundary_tag *left = tag->split_left;
|
||||||
|
|
||||||
|
left->real_size += tag->real_size;
|
||||||
|
left->split_right = tag->split_right;
|
||||||
|
|
||||||
|
if ( tag->split_right != NULL ) tag->split_right->split_left = left;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct boundary_tag* absorb_right( struct boundary_tag *tag )
|
||||||
|
{
|
||||||
|
struct boundary_tag *right = tag->split_right;
|
||||||
|
|
||||||
|
remove_tag( right ); // Remove right from free pages.
|
||||||
|
|
||||||
|
tag->real_size += right->real_size;
|
||||||
|
|
||||||
|
tag->split_right = right->split_right;
|
||||||
|
if ( right->split_right != NULL )
|
||||||
|
right->split_right->split_left = tag;
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct boundary_tag* split_tag( struct boundary_tag* tag )
|
||||||
|
{
|
||||||
|
unsigned int remainder = tag->real_size - sizeof(struct boundary_tag) - tag->size;
|
||||||
|
|
||||||
|
struct boundary_tag *new_tag =
|
||||||
|
(struct boundary_tag*)((unsigned int)tag + sizeof(struct boundary_tag) + tag->size);
|
||||||
|
|
||||||
|
new_tag->magic = LIBALLOC_MAGIC;
|
||||||
|
new_tag->real_size = remainder;
|
||||||
|
|
||||||
|
new_tag->next = NULL;
|
||||||
|
new_tag->prev = NULL;
|
||||||
|
|
||||||
|
new_tag->split_left = tag;
|
||||||
|
new_tag->split_right = tag->split_right;
|
||||||
|
|
||||||
|
if (new_tag->split_right != NULL) new_tag->split_right->split_left = new_tag;
|
||||||
|
tag->split_right = new_tag;
|
||||||
|
|
||||||
|
tag->real_size -= new_tag->real_size;
|
||||||
|
|
||||||
|
insert_tag( new_tag, -1 );
|
||||||
|
|
||||||
|
return new_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ***************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static struct boundary_tag* allocate_new_tag( unsigned int size )
|
||||||
|
{
|
||||||
|
unsigned int pages;
|
||||||
|
unsigned int usage;
|
||||||
|
struct boundary_tag *tag;
|
||||||
|
|
||||||
|
// This is how much space is required.
|
||||||
|
usage = size + sizeof(struct boundary_tag);
|
||||||
|
|
||||||
|
// Perfect amount of space
|
||||||
|
pages = usage / l_pageSize;
|
||||||
|
if ( (usage % l_pageSize) != 0 ) pages += 1;
|
||||||
|
|
||||||
|
// Make sure it's >= the minimum size.
|
||||||
|
if ( pages < l_pageCount ) pages = l_pageCount;
|
||||||
|
|
||||||
|
tag = (struct boundary_tag*)liballoc_alloc( pages );
|
||||||
|
|
||||||
|
if ( tag == NULL ) return NULL; // uh oh, we ran out of memory.
|
||||||
|
|
||||||
|
tag->magic = LIBALLOC_MAGIC;
|
||||||
|
tag->size = size;
|
||||||
|
tag->real_size = pages * l_pageSize;
|
||||||
|
tag->index = -1;
|
||||||
|
|
||||||
|
tag->next = NULL;
|
||||||
|
tag->prev = NULL;
|
||||||
|
tag->split_left = NULL;
|
||||||
|
tag->split_right = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Resource allocated %x of %i pages (%i bytes) for %i size.\n", tag, pages, pages * l_pageSize, size );
|
||||||
|
|
||||||
|
l_allocated += pages * l_pageSize;
|
||||||
|
|
||||||
|
printf("Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *malloc(size_t size)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
void *ptr;
|
||||||
|
struct boundary_tag *tag = NULL;
|
||||||
|
|
||||||
|
liballoc_lock();
|
||||||
|
|
||||||
|
if ( l_initialized == 0 )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("%s\n","liballoc initializing.");
|
||||||
|
#endif
|
||||||
|
for ( index = 0; index < MAXEXP; index++ )
|
||||||
|
{
|
||||||
|
l_freePages[index] = NULL;
|
||||||
|
l_completePages[index] = 0;
|
||||||
|
}
|
||||||
|
l_initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = getexp( size ) + MODE;
|
||||||
|
if ( index < MINEXP ) index = MINEXP;
|
||||||
|
|
||||||
|
|
||||||
|
// Find one big enough.
|
||||||
|
tag = l_freePages[ index ]; // Start at the front of the list.
|
||||||
|
while ( tag != NULL )
|
||||||
|
{
|
||||||
|
// If there's enough space in this tag.
|
||||||
|
if ( (tag->real_size - sizeof(struct boundary_tag))
|
||||||
|
>= (size + sizeof(struct boundary_tag) ) )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Tag search found %i >= %i\n",(tag->real_size - sizeof(struct boundary_tag)), (size + sizeof(struct boundary_tag) ) );
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = tag->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// No page found. Make one.
|
||||||
|
if ( tag == NULL )
|
||||||
|
{
|
||||||
|
if ( (tag = allocate_new_tag( size )) == NULL )
|
||||||
|
{
|
||||||
|
liballoc_unlock();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = getexp( tag->real_size - sizeof(struct boundary_tag) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remove_tag( tag );
|
||||||
|
|
||||||
|
if ( (tag->split_left == NULL) && (tag->split_right == NULL) )
|
||||||
|
l_completePages[ index ] -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a free page. Remove it from the free pages list.
|
||||||
|
|
||||||
|
tag->size = size;
|
||||||
|
|
||||||
|
// Removed... see if we can re-use the excess space.
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Found tag with %i bytes available (requested %i bytes, leaving %i), which has exponent: %i (%i bytes)\n", tag->real_size - sizeof(struct boundary_tag), size, tag->real_size - size - sizeof(struct boundary_tag), index, 1<<index );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned int remainder = tag->real_size - size - sizeof( struct boundary_tag ) * 2; // Support a new tag + remainder
|
||||||
|
|
||||||
|
if ( ((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<<MINEXP))*/ )
|
||||||
|
{
|
||||||
|
int childIndex = getexp( remainder );
|
||||||
|
|
||||||
|
if ( childIndex >= 0 )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Seems to be splittable: %i >= 2^%i .. %i\n", remainder, childIndex, (1<<childIndex) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct boundary_tag *new_tag = split_tag( tag );
|
||||||
|
|
||||||
|
new_tag = new_tag; // Get around the compiler warning about unused variables.
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Old tag has become %i bytes, new tag is now %i bytes (%i exp)\n", tag->real_size, new_tag->real_size, new_tag->index );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ptr = (void*)((unsigned int)tag + sizeof( struct boundary_tag ) );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
l_inuse += size;
|
||||||
|
printf("malloc: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 );
|
||||||
|
dump_array();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
liballoc_unlock();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void free(void *ptr)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
struct boundary_tag *tag;
|
||||||
|
|
||||||
|
if ( ptr == NULL ) return;
|
||||||
|
|
||||||
|
liballoc_lock();
|
||||||
|
|
||||||
|
|
||||||
|
tag = (struct boundary_tag*)((unsigned int)ptr - sizeof( struct boundary_tag ));
|
||||||
|
|
||||||
|
if ( tag->magic != LIBALLOC_MAGIC )
|
||||||
|
{
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
l_inuse -= tag->size;
|
||||||
|
printf("free: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// MELT LEFT...
|
||||||
|
while ( (tag->split_left != NULL) && (tag->split_left->index >= 0) )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Melting tag left into available memory. Left was %i, becomes %i (%i)\n", tag->split_left->real_size, tag->split_left->real_size + tag->real_size, tag->split_left->real_size );
|
||||||
|
#endif
|
||||||
|
tag = melt_left( tag );
|
||||||
|
remove_tag( tag );
|
||||||
|
}
|
||||||
|
|
||||||
|
// MELT RIGHT...
|
||||||
|
while ( (tag->split_right != NULL) && (tag->split_right->index >= 0) )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Melting tag right into available memory. This was was %i, becomes %i (%i)\n", tag->real_size, tag->split_right->real_size + tag->real_size, tag->split_right->real_size );
|
||||||
|
#endif
|
||||||
|
tag = absorb_right( tag );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Where is it going back to?
|
||||||
|
index = getexp( tag->real_size - sizeof(struct boundary_tag) );
|
||||||
|
if ( index < MINEXP ) index = MINEXP;
|
||||||
|
|
||||||
|
// A whole, empty block?
|
||||||
|
if ( (tag->split_left == NULL) && (tag->split_right == NULL) )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( l_completePages[ index ] == MAXCOMPLETE )
|
||||||
|
{
|
||||||
|
// Too many standing by to keep. Free this one.
|
||||||
|
unsigned int pages = tag->real_size / l_pageSize;
|
||||||
|
|
||||||
|
if ( (tag->real_size % l_pageSize) != 0 ) pages += 1;
|
||||||
|
if ( pages < l_pageCount ) pages = l_pageCount;
|
||||||
|
|
||||||
|
liballoc_free( tag, pages );
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
l_allocated -= pages * l_pageSize;
|
||||||
|
printf("Resource freeing %x of %i pages\n", tag, pages );
|
||||||
|
dump_array();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
liballoc_unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
l_completePages[ index ] += 1; // Increase the count of complete pages.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ..........
|
||||||
|
|
||||||
|
|
||||||
|
insert_tag( tag, index );
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Returning tag with %i bytes (requested %i bytes), which has exponent: %i\n", tag->real_size, tag->size, index );
|
||||||
|
dump_array();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
liballoc_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void* calloc(size_t nobj, size_t size)
|
||||||
|
{
|
||||||
|
int real_size;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
real_size = nobj * size;
|
||||||
|
|
||||||
|
p = malloc( real_size );
|
||||||
|
|
||||||
|
liballoc_memset( p, 0, real_size );
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void* realloc(void *p, size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
struct boundary_tag *tag;
|
||||||
|
int real_size;
|
||||||
|
|
||||||
|
if ( size == 0 )
|
||||||
|
{
|
||||||
|
free( p );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ( p == NULL ) return malloc( size );
|
||||||
|
|
||||||
|
if ( liballoc_lock != NULL ) liballoc_lock(); // lockit
|
||||||
|
tag = (struct boundary_tag*)((unsigned int)p - sizeof( struct boundary_tag ));
|
||||||
|
real_size = tag->size;
|
||||||
|
if ( liballoc_unlock != NULL ) liballoc_unlock();
|
||||||
|
|
||||||
|
if ( real_size > size ) real_size = size;
|
||||||
|
|
||||||
|
ptr = malloc( size );
|
||||||
|
liballoc_memcpy( ptr, p, real_size );
|
||||||
|
free( p );
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user