404 lines
12 KiB
C
404 lines
12 KiB
C
/*
|
|
File: ContFramePool.C
|
|
|
|
Author:
|
|
Date :
|
|
|
|
*/
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/*
|
|
POSSIBLE IMPLEMENTATION
|
|
-----------------------
|
|
|
|
The class SimpleFramePool in file "simple_frame_pool.H/C" describes an
|
|
incomplete vanilla implementation of a frame pool that allocates
|
|
*single* frames at a time. Because it does allocate one frame at a time,
|
|
it does not guarantee that a sequence of frames is allocated contiguously.
|
|
This can cause problems.
|
|
|
|
The class ContFramePool has the ability to allocate either single frames,
|
|
or sequences of contiguous frames. This affects how we manage the
|
|
free frames. In SimpleFramePool it is sufficient to maintain the free
|
|
frames.
|
|
In ContFramePool we need to maintain free *sequences* of frames.
|
|
|
|
This can be done in many ways, ranging from extensions to bitmaps to
|
|
free-lists of frames etc.
|
|
|
|
IMPLEMENTATION:
|
|
|
|
One simple way to manage sequences of free frames is to add a minor
|
|
extension to the bitmap idea of SimpleFramePool: Instead of maintaining
|
|
whether a frame is FREE or ALLOCATED, which requires one bit per frame,
|
|
we maintain whether the frame is FREE, or ALLOCATED, or HEAD-OF-SEQUENCE.
|
|
The meaning of FREE is the same as in SimpleFramePool.
|
|
If a frame is marked as HEAD-OF-SEQUENCE, this means that it is allocated
|
|
and that it is the first such frame in a sequence of frames. Allocated
|
|
frames that are not first in a sequence are marked as ALLOCATED.
|
|
|
|
NOTE: If we use this scheme to allocate only single frames, then all
|
|
frames are marked as either FREE or HEAD-OF-SEQUENCE.
|
|
|
|
NOTE: In SimpleFramePool we needed only one bit to store the state of
|
|
each frame. Now we need two bits. In a first implementation you can choose
|
|
to use one char per frame. This will allow you to check for a given status
|
|
without having to do bit manipulations. Once you get this to work,
|
|
revisit the implementation and change it to using two bits. You will get
|
|
an efficiency penalty if you use one char (i.e., 8 bits) per frame when
|
|
two bits do the trick.
|
|
|
|
DETAILED IMPLEMENTATION:
|
|
|
|
How can we use the HEAD-OF-SEQUENCE state to implement a contiguous
|
|
allocator? Let's look a the individual functions:
|
|
|
|
Constructor: Initialize all frames to FREE, except for any frames that you
|
|
need for the management of the frame pool, if any.
|
|
|
|
get_frames(_n_frames): Traverse the "bitmap" of states and look for a
|
|
sequence of at least _n_frames entries that are FREE. If you find one,
|
|
mark the first one as HEAD-OF-SEQUENCE and the remaining _n_frames-1 as
|
|
ALLOCATED.
|
|
|
|
release_frames(_first_frame_no): Check whether the first frame is marked as
|
|
HEAD-OF-SEQUENCE. If not, something went wrong. If it is, mark it as FREE.
|
|
Traverse the subsequent frames until you reach one that is FREE or
|
|
HEAD-OF-SEQUENCE. Until then, mark the frames that you traverse as FREE.
|
|
|
|
mark_inaccessible(_base_frame_no, _n_frames): This is no different than
|
|
get_frames, without having to search for the free sequence. You tell the
|
|
allocator exactly which frame to mark as HEAD-OF-SEQUENCE and how many
|
|
frames after that to mark as ALLOCATED.
|
|
|
|
needed_info_frames(_n_frames): This depends on how many bits you need
|
|
to store the state of each frame. If you use a char to represent the state
|
|
of a frame, then you need one info frame for each FRAME_SIZE frames.
|
|
|
|
A WORD ABOUT RELEASE_FRAMES():
|
|
|
|
When we releae a frame, we only know its frame number. At the time
|
|
of a frame's release, we don't know necessarily which pool it came
|
|
from. Therefore, the function "release_frame" is static, i.e.,
|
|
not associated with a particular frame pool.
|
|
|
|
This problem is related to the lack of a so-called "placement delete" in
|
|
C++. For a discussion of this see Stroustrup's FAQ:
|
|
http://www.stroustrup.com/bs_faq2.html#placement-delete
|
|
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* DEFINES */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* -- (none) -- */
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* INCLUDES */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
#include "cont_frame_pool.H"
|
|
#include "console.H"
|
|
#include "utils.H"
|
|
#include "assert.H"
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* DATA STRUCTURES */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* -- (none) -- */
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* CONSTANTS */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* -- (none) -- */
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* FORWARDS */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* -- (none) -- */
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* METHODS FOR CLASS C o n t F r a m e P o o l */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
ContFramePool* ContFramePool::pools = (ContFramePool *) FRAME_SIZE; // List of frame pools, managed by the class
|
|
unsigned int ContFramePool::nPools = 0; // Number of pools being managed
|
|
|
|
ContFramePool::ContFramePool(unsigned long _base_frame_no,
|
|
unsigned long _n_frames,
|
|
unsigned long _info_frame_no,
|
|
unsigned long _n_info_frames)
|
|
{
|
|
// Bitmap must fit in a single frame!
|
|
// NOTE: In theory, we don't need to make the bitmap any larger,
|
|
// since as stated in the instructions it is already big enough to
|
|
// hold for 128MB of memory with one bit per frame, so should still
|
|
// be enough for 64MB of memory with 2 bits per frame.
|
|
// Assertion changed to match max size of frames allowed.
|
|
assert(_n_frames <= FRAME_SIZE * 4);
|
|
|
|
base_frame_no = _base_frame_no;
|
|
nframes = _n_frames;
|
|
nFreeFrames = _n_frames;
|
|
info_frame_no = _info_frame_no;
|
|
n_info_frames = _n_info_frames;
|
|
|
|
// If _info_frame_no is zero then we keep management info in the first
|
|
// frame(s), else we use the provided frame(s) to keep management info
|
|
// NOTE: bitmap needs to be allocated with n_info_frames if specified.
|
|
if(info_frame_no == 0)
|
|
{
|
|
bitmap = (unsigned char *) (base_frame_no * FRAME_SIZE);
|
|
}
|
|
else
|
|
{
|
|
bitmap = (unsigned char *) (info_frame_no * FRAME_SIZE * n_info_frames);
|
|
}
|
|
|
|
// Number of frames must "fill" the bitmap!
|
|
assert ((nframes % 8 ) == 0);
|
|
|
|
|
|
// Everything ok. Proceed to mark all bits in the bitmap
|
|
// NOTE: changed to reflect that I need 2 bits per frame now
|
|
for(int i=0; i*4 < _n_frames; i++)
|
|
{
|
|
bitmap[i] = 0xFF;
|
|
}
|
|
|
|
// Mark the first frame as being used if it is being used
|
|
// NOTE: need to mark multiple frames if needed.
|
|
if(info_frame_no == 0)
|
|
{
|
|
bitmap[0] = 0x3F;
|
|
nFreeFrames--;
|
|
}
|
|
else
|
|
{
|
|
unsigned int i = info_frame_no / 4;
|
|
unsigned int r = info_frame_no % 4;
|
|
unsigned char mask = 0x80;
|
|
mask = mask >> r*2;
|
|
|
|
unsigned int c = 0;
|
|
while(c < n_info_frames)
|
|
{
|
|
bitmap[i] = bitmap[i] ^ mask;
|
|
bitmap[i] = bitmap[i] ^ (mask >> 1);
|
|
if(mask == 0x02)
|
|
{
|
|
i++;
|
|
mask = 0x80;
|
|
}
|
|
c++;
|
|
nFreeFrames--;
|
|
}
|
|
|
|
}
|
|
|
|
pools[nPools] = *this;
|
|
nPools += 1;
|
|
|
|
Console::puts("Frame Pool initialized\n");
|
|
}
|
|
|
|
unsigned long ContFramePool::get_frames(unsigned int _n_frames)
|
|
{
|
|
// Are there enough frames left to allocate?
|
|
assert(nFreeFrames > _n_frames);
|
|
|
|
// Find a frame that is not being used and return its frame index.
|
|
// Mark that frame as being used in the bitmap.
|
|
// NOTE: Must be updated to find a sequence of contiguous frames
|
|
// that are not being used and return the index of the head.
|
|
unsigned int frame_no = base_frame_no;
|
|
|
|
// i is being used as the frame_no / 4
|
|
// j is frame_no % 4
|
|
// together, they will give the actual frame_no.
|
|
// c is used as a counter to count a squence of free frames.
|
|
unsigned int i = 0;
|
|
unsigned int j = 0;
|
|
unsigned int c = 0;
|
|
|
|
while (true)
|
|
{
|
|
unsigned char mask = 0x80 >> (j*2);
|
|
// check every 2 bits for a free frame in the bitmap
|
|
while((mask & bitmap[i]) == 0 || ((mask >> 1) & bitmap[i]) == 0)
|
|
{
|
|
if(mask != 0x02)
|
|
{
|
|
j++;
|
|
mask = mask >> 2;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
j = 0;
|
|
mask = 0x80;
|
|
}
|
|
}
|
|
// if frame is found, start checking for sequence
|
|
unsigned int temp = i;
|
|
c++;
|
|
while(c < _n_frames)
|
|
{
|
|
if(mask != 0x02)
|
|
{
|
|
mask = mask >> 2;
|
|
}
|
|
else
|
|
{
|
|
temp++;
|
|
mask = 0x80;
|
|
}
|
|
if((mask & bitmap[temp]) != 0 && ((mask >> 1) & bitmap[temp]) != 0)
|
|
{
|
|
c++;
|
|
}
|
|
else
|
|
{
|
|
c = 0;
|
|
break;
|
|
}
|
|
}
|
|
if(c == _n_frames)
|
|
{
|
|
nFreeFrames -= _n_frames;
|
|
break;
|
|
}
|
|
}
|
|
|
|
frame_no += i*4 + j;
|
|
|
|
// Update bitmap
|
|
// First: clear most significant bit to mark head of sequence.
|
|
bitmap[i] = bitmap[i] ^ (0x80 >> (j*2));
|
|
// Second: clear both bits for all remaining frames in the sequence.
|
|
c = 1;
|
|
unsigned char mask = 0x80 >> j*2;
|
|
unsigned int temp = i;
|
|
while(c < _n_frames)
|
|
{
|
|
if(mask != 0x02)
|
|
{
|
|
mask = mask >> 2;
|
|
}
|
|
else
|
|
{
|
|
temp++;
|
|
mask = 0x80;
|
|
}
|
|
|
|
bitmap[temp] = bitmap[temp] ^ mask;
|
|
bitmap[temp] = bitmap[temp] ^ (mask >> 1);
|
|
c++;
|
|
}
|
|
|
|
return (frame_no);
|
|
}
|
|
|
|
void ContFramePool::mark_inaccessible(unsigned long _base_frame_no,
|
|
unsigned long _n_frames)
|
|
{
|
|
// Mark all frames in the range as being used.
|
|
int i ;
|
|
for(i = _base_frame_no; i < _base_frame_no + _n_frames; i++){
|
|
mark_inaccessible(i);
|
|
}
|
|
nFreeFrames -= _n_frames;
|
|
}
|
|
|
|
void ContFramePool::mark_inaccessible(unsigned long _frame_no)
|
|
{
|
|
// Let's first do a range check.
|
|
assert ((_frame_no >= base_frame_no) && (_frame_no < base_frame_no + nframes));
|
|
|
|
unsigned int bitmap_index = (_frame_no - base_frame_no) / 4;
|
|
unsigned char mask = 0x80 >> ((_frame_no - base_frame_no) % 4) * 2;
|
|
|
|
// Is the frame being used already?
|
|
assert(((bitmap[bitmap_index] & mask) != 0) && (bitmap[bitmap_index] & (mask >> 1)) != 0);
|
|
|
|
// Update bitmap
|
|
bitmap[bitmap_index] ^= mask;
|
|
bitmap[bitmap_index] ^= mask >> 1;
|
|
nFreeFrames--;
|
|
}
|
|
|
|
void ContFramePool::release_frames(unsigned long _frame_no)
|
|
{
|
|
unsigned int i = 0;
|
|
while(i < nPools)
|
|
{
|
|
if(_frame_no <= pools[i].base_frame_no || _frame_no > (pools[i].base_frame_no + pools[i].nframes))
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
pools[i].release_frames_here(_frame_no);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ContFramePool::release_frames_here(unsigned long _first_frame_no)
|
|
{
|
|
unsigned char * bitmap = this->bitmap;
|
|
|
|
unsigned int bitmap_index = (_first_frame_no - base_frame_no) / 4;
|
|
unsigned char mask = 0x80 >> ((_first_frame_no - base_frame_no) % 4) * 2;
|
|
|
|
if(!((bitmap[bitmap_index] & mask) == 0 && (bitmap[bitmap_index] & (mask >> 1)) != 0))
|
|
{
|
|
if((bitmap[bitmap_index] & mask) != 0 && (bitmap[bitmap_index] & (mask >> 1)) != 0)
|
|
{
|
|
Console::puts("Error, Frame being released is not being used\n");
|
|
assert(false);
|
|
}
|
|
Console::puts("Error, Frame being released is not head of sequence\n");
|
|
assert(false);
|
|
}
|
|
|
|
bitmap[bitmap_index] ^= mask;
|
|
nFreeFrames++;
|
|
|
|
if(mask != 0x02)
|
|
{
|
|
mask = mask >> 2;
|
|
}
|
|
else
|
|
{
|
|
mask = 0x80;
|
|
bitmap_index++;
|
|
}
|
|
|
|
while(bitmap[bitmap_index] & mask == 0 && (bitmap[bitmap_index] & (mask >> 1)) == 0)
|
|
{
|
|
bitmap[bitmap_index] ^= mask;
|
|
bitmap[bitmap_index] ^= (mask >> 1);
|
|
if(mask != 0x02)
|
|
{
|
|
mask = mask >> 2;
|
|
}
|
|
else
|
|
{
|
|
mask = 0x80;
|
|
bitmap_index++;
|
|
}
|
|
nFreeFrames++;
|
|
}
|
|
}
|
|
|
|
unsigned long ContFramePool::needed_info_frames(unsigned long _n_frames)
|
|
{
|
|
return (_n_frames / (FRAME_SIZE * 4)) + (_n_frames % (FRAME_SIZE * 4) > 0 ? 1 : 0);
|
|
}
|