cfad47cfa3/tads3/vmpoolim.cpp
Commiter: Nikos Chantziaras
Author: Nikos Chantziaras
Revision: cfad47cfa3
File Size: 10.6 KB
(June 01, 2009 20:54 UTC) Almost 3 years ago
Initial commit.
/*
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
vmpool.cpp - constant pool - in-memory (non-swapping) implementation
Function
Notes
Modified
10/20/98 MJRoberts - Creation
*/
#include <stdlib.h>
#include <memory.h>
#include "t3std.h"
#include "vmpool.h"
/* ------------------------------------------------------------------------ */
/*
* In-memory pool implementation. This pool implementation pre-loads
* all available pages in the pool and keeps the complete pool in memory
* at all times.
*/
/*
* delete the pool's resources - this is called from our destructor, and
* can also be called explicitly to reset the pool
*/
void CVmPoolInMem::terminate_nv()
{
/* free any pages we allocated from the backing store */
free_backing_pages();
/* free all of the dynamic object handles */
while (dyn_head_ != 0)
{
CVmPoolDynObj *nxt;
/* note the next object */
nxt = dyn_head_->get_next();
/* delete this object */
t3free(dyn_head_);
/* move on to the next one */
dyn_head_ = nxt;
}
/* we no longer have anything in the list */
dyn_head_ = dyn_tail_ = 0;
/* we no longer have any dynamic pages */
first_dyn_page_ = 0;
}
/*
* free pages that we allocated from the backing store
*/
void CVmPoolInMem::free_backing_pages()
{
size_t i;
pool_ofs_t ofs;
CVmPool_pg *info;
/*
* delete any dynamically-allocated pages (these are not managed by
* the backing store)
*/
for (i = first_dyn_page_, info = &pages_[i] ; i < page_slots_ ;
++i, ++info)
{
/* if this slot was allocated, delete it */
if (info->mem != 0)
{
/* free the memory */
t3free((char *)info->mem);
/* note that we've freed it */
info->mem = 0;
}
}
/* if there's no backing store, there's nothing to do */
if (backing_store_ == 0)
return;
/*
* Run through the page array and delete each allocated page. Since
* we allocate pages through the backing store, delete pages through
* the backing store.
*/
for (i = 0, info = pages_, ofs = 0 ; i < first_dyn_page_ ;
++i, ++info, ofs += page_size_)
{
/* if this slot was allocated, delete it */
if (info->mem != 0)
{
/* delete the page */
backing_store_->vmpbs_free_page(info->mem, ofs, page_size_);
/* forget it */
info->mem = 0;
}
}
}
/*
* initialize
*/
void CVmPoolInMem::attach_backing_store(CVmPoolBackingStore *backing_store)
{
size_t ofs;
size_t i;
CVmPool_pg *info;
/* do the normal initialization to allocate the page slots */
CVmPoolPaged::attach_backing_store(backing_store);
/*
* set the initial dynamic page index - this will be the first page
* after all of the fixed pages we load from the backing store
*/
first_dyn_page_ = page_slots_;
/* load all of the pages */
for (i = 0, info = pages_, ofs = 0 ; i < page_slots_ ;
++i, ++info, ofs += page_size_)
{
size_t load_size;
/* determine how much memory we really need for this page */
load_size = backing_store_->vmpbs_get_page_size(ofs, page_size_);
/* allocate and load the page */
info->mem = backing_store_->vmpbs_alloc_and_load_page(
ofs, page_size_, load_size);
}
}
/*
* Detach from the backing store
*/
void CVmPoolInMem::detach_backing_store()
{
/* release the backing pages */
free_backing_pages();
/* inherit default */
CVmPoolPaged::detach_backing_store();
}
/* ------------------------------------------------------------------------ */
/*
* Dynamic interface implementation
*/
/*
* Allocate space in the dynamic pool
*/
CVmPoolDynObj *CVmPoolInMem::dynpool_alloc(size_t len)
{
CVmPoolDynObj *cur;
/*
* if the requested size exceeds the page size, we can't allocate
* it, since each request must fit within a single page
*/
if (len > page_size_)
return 0;
/*
* First, see if we can find a free pool object that we've already
* allocated that will fill the request
*/
for (cur = dyn_head_ ; cur != 0 ; cur = cur->get_next())
{
/* if this object is free, and it's big enough, use it */
if (cur->is_free() && cur->get_len() >= len)
{
/*
* if this object is at least a little bigger than the
* request, create a new object to hold the balance of this
* object, so that the balance can be allocated separately
*/
if (cur->get_len() > len + 63)
{
CVmPoolDynObj *new_obj;
/*
* create a new object, using the space remaining in the
* old object after the requested amount of space
*/
new_obj = new CVmPoolDynObj(cur->get_ofs() + len,
cur->get_len() - len);
/* reduce the old object to the requested size */
cur->set_len(len);
/* link the new object in after the old object */
insert_dyn(cur, new_obj);
/* the new object is free */
new_obj->set_free(TRUE);
}
/* this object is now in use */
cur->set_free(FALSE);
/* return the object we found */
return cur;
}
}
/*
* We didn't find any free memory in any existing pages where we
* could fill the request. So, we must allocate a new page. First,
* allocate a new page slot.
*/
alloc_page_slots(page_slots_ + 1);
/* allocate space for the page data */
pages_[page_slots_ - 1].mem = (char *)t3malloc(page_size_);
/*
* if the requested size wouldn't leave much additional space on the
* page, simply give the entire page to the new object
*/
if (len + 63 >= page_size_)
len = page_size_;
/* create a new dynamic pool handle for the new object */
cur = new CVmPoolDynObj(get_page_start_ofs(page_slots_ - 1), len);
/* link it in at the end of the list */
append_dyn(cur);
/*
* if there's any space left over, create yet another object to
* cover the free space remaining on the page
*/
if (len < page_size_)
{
CVmPoolDynObj *f;
/* create a new dynamic pool handle for the new object */
f = new CVmPoolDynObj(get_page_start_ofs(page_slots_ - 1) + len,
page_size_ - len);
/* mark it as free */
f->set_free(TRUE);
/* link it in at the end of the list */
append_dyn(f);
}
/* return the new object */
return cur;
}
/*
* Delete a dynamic object
*/
void CVmPoolInMem::dynpool_delete(CVmPoolDynObj *obj)
{
CVmPoolDynObj *cur;
size_t pg;
/* mark this object as free */
obj->set_free(TRUE);
/* note the page containing this object */
pg = get_page_for_ofs(obj->get_ofs());
/*
* Combine this object with any consecutive objects in the same
* page. First, look for objects before this object.
*/
for (cur = obj->get_prev() ;
cur != 0 && cur->is_free()
&& get_page_for_ofs(cur->get_ofs()) == pg ;
cur = cur->get_prev())
{
/*
* cur precedes obj, is on the same page, and is also free -
* combine cur and obj into cur
*/
cur->set_len(cur->get_len() + obj->get_len());
/* unlink obj from the list, since it's no longer needed */
unlink_dyn(obj);
/* delete the original object */
delete obj;
/* forget about obj - cur now encompasses it */
obj = cur;
}
/*
* Now combine any consecutive objects that follow
*/
for (cur = obj->get_next() ;
cur != 0 && cur->is_free()
&& get_page_for_ofs(cur->get_ofs()) == pg ; )
{
/*
* cur follows obj, is on the same page, and is also free -
* combine cur and obj into obj
*/
obj->set_len(obj->get_len() + cur->get_len());
/* unlink cur from the list, since it's no longer needed */
unlink_dyn(cur);
/* delete the second object */
delete cur;
/* move on to the next object */
cur = obj->get_next();
}
}
/*
* Compress the dynamic portion of the pool
*/
void CVmPoolInMem::dynpool_compress()
{
// $$$
}
/*
* Append a dynamic handle to the end of our list
*/
void CVmPoolInMem::append_dyn(CVmPoolDynObj *obj)
{
/* this goes at the end, so there's nothing after this object */
obj->set_next(0);
/* the old tail will precede this object in the list */
obj->set_prev(dyn_tail_);
/*
* if the list is empty, this is the new head; otherwise, set the
* old tail's forward pointer to the new item
*/
if (dyn_tail_ == 0)
dyn_head_ = obj;
else
dyn_tail_->set_next(obj);
/* this is now the tail item */
dyn_tail_ = obj;
}
/*
* Unlink a dynamic handle from the list
*/
void CVmPoolInMem::unlink_dyn(CVmPoolDynObj *obj)
{
/*
* if there's a previous item, set its forward pointer; otherwise,
* advance the list head past the item we're unlinking
*/
if (obj->get_prev() != 0)
obj->get_prev()->set_next(obj->get_next());
else
dyn_head_ = obj->get_next();
/*
* if there's a following item, set its back pointer; otherwise,
* move the list tail back over the item we're unlinking
*/
if (obj->get_next() != 0)
obj->get_next()->set_prev(obj);
else
dyn_tail_ = obj->get_prev();
}
/*
* Insert a dynamic handle into the list after the given object
*/
void CVmPoolInMem::insert_dyn(CVmPoolDynObj *obj, CVmPoolDynObj *new_obj)
{
/* the old following object (after obj) will now follow new_obj */
new_obj->set_next(obj->get_next());
/* obj will precede new_obj */
new_obj->set_prev(obj);
/* new_obj will follow the old object */
obj->set_next(new_obj);
/*
* if another object follows, set its back pointer to point to the
* new object; otherwise, set the list tail pointer
*/
if (new_obj->get_next() != 0)
new_obj->get_next()->set_prev(new_obj);
else
dyn_tail_ = new_obj;
} |