Oh, so that explains it. I went over the code extensively - even rewriting it in my own idiom so that I understood it better - and I still missed that. Now that you've explained it, it seems so clear all of a sudden.
BTW, you may want to check to see if you have an off-by-one error in the code that calculates the return value as well; in the existing code, it looks as if it returns the last byte of the header, not the byte following it.
This is the version I re-wrote (including that last correction that you found), if it makes any difference. I mostly just set all the constants into [tt]#define[/tt]s and changed a few names for my own benefit, but I did make one change with how it calculates the return pointer that I think makes the code considerably simpler and probably marginally faster (since it reduces the amount of code in a loop).
Code: Select all
#include "kmem.h"
BIT blocks[MAXBLOCKS];
void* kmalloc(int size)
{
int* allocmem=NULL; // the pointer to the allocated memory
int searchedsize=0; // the size of the free blocks currently being tested
int blockpos=0; // the first marker for the allocated block
int currentpos=0; // the block flag currently being tested
int setblock=0; // current block to set
// Reserve room before the allocated space for storing the header.
size += HEADERSIZE;
// Search for a block of memory greater than or equal to the
// size we need. We will go through the RAM sequentially.
// If the next block is taken, reset searchedsize
// which contains the current block's size.
// If the next block is free, add on to searchedsize.
// Once we find a large enough block, move on.
while (searchedsize <= size)
{
if (CLEAR == blocks[currentpos])
{
// If blockpos is zero, then this is the
// beginning of a free block.
if (0 == blockpos)
{
// Set blockpos to the current position.
blockpos = currentpos;
}
searchedsize += BLOCKSIZE;
} else {
searchedsize = 0;
// We didn't find anything yet, clear blockpos
blockpos = 0;
}
currentpos++;
// if we have run passed the total physical memory,
// return an error
if (currentpos > MAXBLOCKS)
{
return NULL;
}
}
// Set the block as used in the bitmap.
// Start by searching at the beginning of the allocated block
// until we get past the currentpos which is the end of the
// allocated block. Then for each part of our bitmap,
// mark it as taken.
for (setblock = blockpos; setblock < currentpos; setblock++)
{
blocks[setblock] = SET;
}
// set the allocated memory pointer to
// the beginning of the memory block,
// with the appropriate offset for the system memory
allocmem = (int *)((blockpos * BLOCKSIZE) + RESERVED_MEM);
// Now we must write our header. The header contains searchedsize,
// the length of our block in bytes. Set the address of header to
// allocmem to change header to searchedsize.
*allocmem = searchedsize;
// Last, increase allocmem by HEADERSIZE+1 so that the
// allocated space begins at the byte following the header.
// Note that allocmem has to be cast to void* BEFORE the
// calculations, so that the pointer arithmetic is in
// bytes rather than in ints.
return (HEADERSIZE + 1 + (void*)(allocmem));
}
The header file kmem.h contains
Code: Select all
// kmmem.h - header file for the system memory allocator
#ifndef ___KMEM_H___
#define ___KMEM_H___
#ifndef NULL
#define NULL '\000'
#endif
typedef enum {CLEAR = 0, SET = 1} BIT;
// basic constants
#define KILOBYTE 1024
#define MEGABYTE (KILOBYTE * 1024)
// physical memory size in megabytes
#define MEMSIZE 16
// size of starting memory reserved by the system
#define RESERVED_MEM (2 * MEGABYTE)
// size of a basic allocation block
#define BLOCKSIZE (8 * KILOBYTE)
// Total number of blocks available for allocation
#define MAXBLOCKS (((MEMSIZE * MEGABYTE) - RESERVED_MEM) / BLOCKSIZE)
// size of the allocated memory header
#define HEADERSIZE 20
void* kmalloc(int);
void kfree(void*);
#endif
Since the [tt]#define[/tt]s are all based on constants, the compiler should be smart enough to precalculate them rather than have them calculated at runtime.
Let me know if this helps at all or not. Since I don't have the rest of your code, I don't know if it would work or not as it is, but I do know it compiles correctly under Dev-C++ 5.0beta.
EDIT: Replaced [tt]BOOL[/tt], [tt]TRUE[/tt] and [tt]FALSE[/tt] with the [tt]BIT[/tt] enumeration.
I can't seem to leave well enough alone; now I keep thinking of how I could implement [tt]blocks[[]][/tt] as bit strings. If only I could put so much effort into my own projects...