fix nasty list alloc bug and add spinlock
This commit is contained in:
@ -72,6 +72,7 @@ void LinkedListAllocator::dump_free_memory() {
|
|||||||
* Beschreibung: Einen neuen Speicherblock allozieren. *
|
* Beschreibung: Einen neuen Speicherblock allozieren. *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
void* LinkedListAllocator::alloc(unsigned int req_size) {
|
void* LinkedListAllocator::alloc(unsigned int req_size) {
|
||||||
|
this->lock.acquire();
|
||||||
|
|
||||||
/* Hier muess Code eingefuegt werden */
|
/* Hier muess Code eingefuegt werden */
|
||||||
// NOTE: next pointer zeigt auf headeranfang, returned wird zeiger auf anfang des nutzbaren freispeichers
|
// NOTE: next pointer zeigt auf headeranfang, returned wird zeiger auf anfang des nutzbaren freispeichers
|
||||||
@ -80,6 +81,7 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
|
|
||||||
if (this->free_start == NULL) {
|
if (this->free_start == NULL) {
|
||||||
log << ERROR << " - No free memory remaining :(" << endl;
|
log << ERROR << " - No free memory remaining :(" << endl;
|
||||||
|
this->lock.release();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
|
|
||||||
free_block_t* current = this->free_start;
|
free_block_t* current = this->free_start;
|
||||||
do {
|
do {
|
||||||
if (current->size >= rreq_size) {
|
if (current->size >= rreq_size) { // Size doesn't contain header, only usable
|
||||||
// Current block large enough
|
// Current block large enough
|
||||||
// We now have: [<> | current | <>]
|
// We now have: [<> | current | <>]
|
||||||
|
|
||||||
@ -111,6 +113,7 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
// This shouldn't be a problem since the block gets removed from the list later
|
// This shouldn't be a problem since the block gets removed from the list later
|
||||||
new_next->next = current->next;
|
new_next->next = current->next;
|
||||||
new_next->size = current->size - (rreq_size + sizeof(free_block_t));
|
new_next->size = current->size - (rreq_size + sizeof(free_block_t));
|
||||||
|
new_next->allocated = false;
|
||||||
|
|
||||||
current->next = new_next; // We want to reach the next free block from the allocated block
|
current->next = new_next; // We want to reach the next free block from the allocated block
|
||||||
current->size = rreq_size;
|
current->size = rreq_size;
|
||||||
@ -134,13 +137,27 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Block aushängen
|
// Block aushängen
|
||||||
|
// If block was cut this is obvious, because current->next is a free block
|
||||||
|
// If block wasn't cut it also works as current was a free block before, so it's next
|
||||||
|
// block should also be free
|
||||||
free_block_t* previous = LinkedListAllocator::find_previous_block(current);
|
free_block_t* previous = LinkedListAllocator::find_previous_block(current);
|
||||||
previous->next = current->next;
|
previous->next = current->next; // Current block was free so previous block pointed at it
|
||||||
current->allocated = true;
|
current->allocated = true;
|
||||||
|
|
||||||
// We leave the current->next pointer intact although the block is allocated
|
// We leave the current->next pointer intact although the block is allocated
|
||||||
// to allow easier merging of adjacent free blocks
|
// to allow easier merging of adjacent free blocks
|
||||||
|
|
||||||
|
// NOTE: Checking list integrity
|
||||||
|
free_block_t* c = current;
|
||||||
|
log << DEBUG << "Checking list Integrity" << endl;
|
||||||
|
while (c->allocated) {
|
||||||
|
log << DEBUG << hex << (unsigned int)c << endl;
|
||||||
|
c = c->next;
|
||||||
|
}
|
||||||
|
log << DEBUG << "Finished check" << endl;
|
||||||
|
|
||||||
|
log << DEBUG << "Returning memory address " << hex << ((unsigned int)current + sizeof(free_block_t)) << endl;
|
||||||
|
this->lock.release();
|
||||||
return (void*)((unsigned int)current + sizeof(free_block_t)); // Speicheranfang, nicht header
|
return (void*)((unsigned int)current + sizeof(free_block_t)); // Speicheranfang, nicht header
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +165,7 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
} while (current != this->free_start); // Stop when arriving at the first block again
|
} while (current != this->free_start); // Stop when arriving at the first block again
|
||||||
|
|
||||||
log << ERROR << " - More memory requested than available :(" << endl;
|
log << ERROR << " - More memory requested than available :(" << endl;
|
||||||
|
this->lock.release();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,13 +175,21 @@ void* LinkedListAllocator::alloc(unsigned int req_size) {
|
|||||||
* Beschreibung: Einen Speicherblock freigeben. *
|
* Beschreibung: Einen Speicherblock freigeben. *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
void LinkedListAllocator::free(void* ptr) {
|
void LinkedListAllocator::free(void* ptr) {
|
||||||
|
this->lock.acquire();
|
||||||
|
|
||||||
/* Hier muess Code eingefuegt werden */
|
/* Hier muess Code eingefuegt werden */
|
||||||
|
|
||||||
log << DEBUG << "Freeing " << hex << (unsigned int)ptr << endl;
|
// Account for header
|
||||||
|
|
||||||
free_block_t* block_start = (free_block_t*)((unsigned int)ptr - sizeof(free_block_t));
|
free_block_t* block_start = (free_block_t*)((unsigned int)ptr - sizeof(free_block_t));
|
||||||
|
|
||||||
|
log << DEBUG << "Freeing " << hex << (unsigned int)ptr << ", Size: " << block_start->size << endl;
|
||||||
|
|
||||||
|
if (!block_start->allocated) {
|
||||||
|
log << ERROR << "Block already free" << endl;
|
||||||
|
this->lock.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Reenable the freelist if no block was available
|
// Reenable the freelist if no block was available
|
||||||
// This also means that no merging can be done
|
// This also means that no merging can be done
|
||||||
if (this->free_start == NULL) {
|
if (this->free_start == NULL) {
|
||||||
@ -172,6 +198,7 @@ void LinkedListAllocator::free(void* ptr) {
|
|||||||
block_start->next = block_start;
|
block_start->next = block_start;
|
||||||
|
|
||||||
log << TRACE << " - Enabling freelist with one block" << endl;
|
log << TRACE << " - Enabling freelist with one block" << endl;
|
||||||
|
this->lock.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,13 +219,20 @@ void LinkedListAllocator::free(void* ptr) {
|
|||||||
// The <> spaces don't have to exist and next_block could be the same as next_free
|
// The <> spaces don't have to exist and next_block could be the same as next_free
|
||||||
// or previous_free_next the same as block_start
|
// or previous_free_next the same as block_start
|
||||||
// Also next_block and previous_free_next could be allocated blocks
|
// Also next_block and previous_free_next could be allocated blocks
|
||||||
//
|
|
||||||
// If previous_free/next_free and block_start are adjacent and free, they can be merged:
|
// If previous_free/next_free and block_start are adjacent and free, they can be merged:
|
||||||
// - If next_block and next_free are the same block we can merge forward
|
// - If next_block and next_free are the same block we can merge forward
|
||||||
// Should result in: [previous_free | previous_free_next | <> | block_start]
|
// Should result in: [previous_free | previous_free_next | <> | block_start]
|
||||||
// - If previous_free_next and block_start are the same block we can merge backward
|
// - If previous_free_next and block_start are the same block we can merge backward
|
||||||
// Should result in: [block_start]
|
// Should result in: [block_start]
|
||||||
|
|
||||||
|
log << TRACE << "Before doing any merging:" << endl;
|
||||||
|
log << TRACE << "previous_free:" << hex << (unsigned int)previous_free << "Size:" << previous_free->size << "Next:" << (unsigned int)previous_free->next << endl;
|
||||||
|
log << TRACE << "previous_free_next:" << hex << (unsigned int)previous_free_next << "Size:" << previous_free_next->size << "Next:" << (unsigned int)previous_free_next->next << endl;
|
||||||
|
log << TRACE << "block_start:" << hex << (unsigned int)block_start << "Size:" << block_start->size << "Next:" << (unsigned int)block_start->next << endl;
|
||||||
|
log << TRACE << "next_block:" << hex << (unsigned int)next_block << "Size:" << next_block->size << "Next:" << (unsigned int)next_block->next << endl;
|
||||||
|
log << TRACE << "next_free:" << hex << (unsigned int)next_free << "Size:" << next_free->size << "Next:" << (unsigned int)next_free->next << endl;
|
||||||
|
|
||||||
// Try to merge forward ========================================================================
|
// Try to merge forward ========================================================================
|
||||||
if (next_block == next_free) {
|
if (next_block == next_free) {
|
||||||
log << TRACE << " - Merging block forward" << endl;
|
log << TRACE << " - Merging block forward" << endl;
|
||||||
@ -206,10 +240,13 @@ void LinkedListAllocator::free(void* ptr) {
|
|||||||
// Current and next adjacent block can be merged
|
// Current and next adjacent block can be merged
|
||||||
// [previous_free | previous_free_next | <> | block_start | next_free]
|
// [previous_free | previous_free_next | <> | block_start | next_free]
|
||||||
|
|
||||||
|
// [block_start | next_free | next_free->next] => [block_start | next_free->next]
|
||||||
block_start->next = next_free->next; // We make next_free disappear
|
block_start->next = next_free->next; // We make next_free disappear
|
||||||
if (block_start->next == next_free) {
|
if (block_start->next == next_free) {
|
||||||
// If next_free is the only free block it points to itself, so fix that
|
// If next_free is the only free block it points to itself, so fix that
|
||||||
|
// [block_start | next_free], but we want to remove next_free
|
||||||
block_start->next = block_start;
|
block_start->next = block_start;
|
||||||
|
// [block_start]
|
||||||
}
|
}
|
||||||
block_start->size = block_start->size + sizeof(free_block_t) + next_free->size;
|
block_start->size = block_start->size + sizeof(free_block_t) + next_free->size;
|
||||||
|
|
||||||
@ -256,6 +293,7 @@ void LinkedListAllocator::free(void* ptr) {
|
|||||||
|
|
||||||
// Depending on the merging this might write into the block, but doesn't matter
|
// Depending on the merging this might write into the block, but doesn't matter
|
||||||
block_start->allocated = false;
|
block_start->allocated = false;
|
||||||
|
this->lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: I added this
|
// NOTE: I added this
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#define __LinkedListAllocator_include__
|
#define __LinkedListAllocator_include__
|
||||||
|
|
||||||
#include "kernel/Allocator.h"
|
#include "kernel/Allocator.h"
|
||||||
|
#include "lib/SpinLock.h"
|
||||||
#include "user/lib/Logger.h"
|
#include "user/lib/Logger.h"
|
||||||
|
|
||||||
// Format eines freien Blocks, 4 + 4 + 4 Byte
|
// Format eines freien Blocks, 4 + 4 + 4 Byte
|
||||||
@ -41,6 +42,7 @@ private:
|
|||||||
static struct free_block* find_previous_block(struct free_block*);
|
static struct free_block* find_previous_block(struct free_block*);
|
||||||
|
|
||||||
Logger log;
|
Logger log;
|
||||||
|
SpinLock lock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LinkedListAllocator() : log("LL-Alloc") {}
|
LinkedListAllocator() : log("LL-Alloc") {}
|
||||||
|
|||||||
Reference in New Issue
Block a user