2
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
4
* Please see the accompanying license file, LICENSE.TXT, for information
5
* on using and copying this software.
9
vmpool.cpp - constant pool - in-memory (non-swapping) implementation
15
10/20/98 MJRoberts - Creation
25
/* ------------------------------------------------------------------------ */
27
* In-memory pool implementation. This pool implementation pre-loads
28
* all available pages in the pool and keeps the complete pool in memory
33
* delete the pool's resources - this is called from our destructor, and
34
* can also be called explicitly to reset the pool
36
void CVmPoolInMem::terminate_nv()
38
/* free any pages we allocated from the backing store */
41
/* free all of the dynamic object handles */
42
while (dyn_head_ != 0)
46
/* note the next object */
47
nxt = dyn_head_->get_next();
49
/* delete this object */
52
/* move on to the next one */
56
/* we no longer have anything in the list */
57
dyn_head_ = dyn_tail_ = 0;
59
/* we no longer have any dynamic pages */
64
* free pages that we allocated from the backing store
66
void CVmPoolInMem::free_backing_pages()
73
* delete any dynamically-allocated pages (these are not managed by
76
for (i = first_dyn_page_, info = &pages_[i] ; i < page_slots_ ;
79
/* if this slot was allocated, delete it */
83
t3free((char *)info->mem);
85
/* note that we've freed it */
90
/* if there's no backing store, there's nothing to do */
91
if (backing_store_ == 0)
95
* Run through the page array and delete each allocated page. Since
96
* we allocate pages through the backing store, delete pages through
99
for (i = 0, info = pages_, ofs = 0 ; i < first_dyn_page_ ;
100
++i, ++info, ofs += page_size_)
102
/* if this slot was allocated, delete it */
105
/* delete the page */
106
backing_store_->vmpbs_free_page(info->mem, ofs, page_size_);
117
void CVmPoolInMem::attach_backing_store(CVmPoolBackingStore *backing_store)
123
/* do the normal initialization to allocate the page slots */
124
CVmPoolPaged::attach_backing_store(backing_store);
127
* set the initial dynamic page index - this will be the first page
128
* after all of the fixed pages we load from the backing store
130
first_dyn_page_ = page_slots_;
132
/* load all of the pages */
133
for (i = 0, info = pages_, ofs = 0 ; i < page_slots_ ;
134
++i, ++info, ofs += page_size_)
138
/* determine how much memory we really need for this page */
139
load_size = backing_store_->vmpbs_get_page_size(ofs, page_size_);
141
/* allocate and load the page */
142
info->mem = backing_store_->vmpbs_alloc_and_load_page(
143
ofs, page_size_, load_size);
148
* Detach from the backing store
150
void CVmPoolInMem::detach_backing_store()
152
/* release the backing pages */
153
free_backing_pages();
155
/* inherit default */
156
CVmPoolPaged::detach_backing_store();
159
/* ------------------------------------------------------------------------ */
161
* Dynamic interface implementation
165
* Allocate space in the dynamic pool
167
CVmPoolDynObj *CVmPoolInMem::dynpool_alloc(size_t len)
172
* if the requested size exceeds the page size, we can't allocate
173
* it, since each request must fit within a single page
175
if (len > page_size_)
179
* First, see if we can find a free pool object that we've already
180
* allocated that will fill the request
182
for (cur = dyn_head_ ; cur != 0 ; cur = cur->get_next())
184
/* if this object is free, and it's big enough, use it */
185
if (cur->is_free() && cur->get_len() >= len)
188
* if this object is at least a little bigger than the
189
* request, create a new object to hold the balance of this
190
* object, so that the balance can be allocated separately
192
if (cur->get_len() > len + 63)
194
CVmPoolDynObj *new_obj;
197
* create a new object, using the space remaining in the
198
* old object after the requested amount of space
200
new_obj = new CVmPoolDynObj(cur->get_ofs() + len,
201
cur->get_len() - len);
203
/* reduce the old object to the requested size */
206
/* link the new object in after the old object */
207
insert_dyn(cur, new_obj);
209
/* the new object is free */
210
new_obj->set_free(TRUE);
213
/* this object is now in use */
214
cur->set_free(FALSE);
216
/* return the object we found */
222
* We didn't find any free memory in any existing pages where we
223
* could fill the request. So, we must allocate a new page. First,
224
* allocate a new page slot.
226
alloc_page_slots(page_slots_ + 1);
228
/* allocate space for the page data */
229
pages_[page_slots_ - 1].mem = (char *)t3malloc(page_size_);
232
* if the requested size wouldn't leave much additional space on the
233
* page, simply give the entire page to the new object
235
if (len + 63 >= page_size_)
238
/* create a new dynamic pool handle for the new object */
239
cur = new CVmPoolDynObj(get_page_start_ofs(page_slots_ - 1), len);
241
/* link it in at the end of the list */
245
* if there's any space left over, create yet another object to
246
* cover the free space remaining on the page
248
if (len < page_size_)
252
/* create a new dynamic pool handle for the new object */
253
f = new CVmPoolDynObj(get_page_start_ofs(page_slots_ - 1) + len,
256
/* mark it as free */
259
/* link it in at the end of the list */
263
/* return the new object */
268
* Delete a dynamic object
270
void CVmPoolInMem::dynpool_delete(CVmPoolDynObj *obj)
275
/* mark this object as free */
278
/* note the page containing this object */
279
pg = get_page_for_ofs(obj->get_ofs());
282
* Combine this object with any consecutive objects in the same
283
* page. First, look for objects before this object.
285
for (cur = obj->get_prev() ;
286
cur != 0 && cur->is_free()
287
&& get_page_for_ofs(cur->get_ofs()) == pg ;
288
cur = cur->get_prev())
291
* cur precedes obj, is on the same page, and is also free -
292
* combine cur and obj into cur
294
cur->set_len(cur->get_len() + obj->get_len());
296
/* unlink obj from the list, since it's no longer needed */
299
/* delete the original object */
302
/* forget about obj - cur now encompasses it */
307
* Now combine any consecutive objects that follow
309
for (cur = obj->get_next() ;
310
cur != 0 && cur->is_free()
311
&& get_page_for_ofs(cur->get_ofs()) == pg ; )
314
* cur follows obj, is on the same page, and is also free -
315
* combine cur and obj into obj
317
obj->set_len(obj->get_len() + cur->get_len());
319
/* unlink cur from the list, since it's no longer needed */
322
/* delete the second object */
325
/* move on to the next object */
326
cur = obj->get_next();
331
* Compress the dynamic portion of the pool
333
void CVmPoolInMem::dynpool_compress()
339
* Append a dynamic handle to the end of our list
341
void CVmPoolInMem::append_dyn(CVmPoolDynObj *obj)
343
/* this goes at the end, so there's nothing after this object */
346
/* the old tail will precede this object in the list */
347
obj->set_prev(dyn_tail_);
350
* if the list is empty, this is the new head; otherwise, set the
351
* old tail's forward pointer to the new item
356
dyn_tail_->set_next(obj);
358
/* this is now the tail item */
363
* Unlink a dynamic handle from the list
365
void CVmPoolInMem::unlink_dyn(CVmPoolDynObj *obj)
368
* if there's a previous item, set its forward pointer; otherwise,
369
* advance the list head past the item we're unlinking
371
if (obj->get_prev() != 0)
372
obj->get_prev()->set_next(obj->get_next());
374
dyn_head_ = obj->get_next();
377
* if there's a following item, set its back pointer; otherwise,
378
* move the list tail back over the item we're unlinking
380
if (obj->get_next() != 0)
381
obj->get_next()->set_prev(obj);
383
dyn_tail_ = obj->get_prev();
387
* Insert a dynamic handle into the list after the given object
389
void CVmPoolInMem::insert_dyn(CVmPoolDynObj *obj, CVmPoolDynObj *new_obj)
391
/* the old following object (after obj) will now follow new_obj */
392
new_obj->set_next(obj->get_next());
394
/* obj will precede new_obj */
395
new_obj->set_prev(obj);
397
/* new_obj will follow the old object */
398
obj->set_next(new_obj);
401
* if another object follows, set its back pointer to point to the
402
* new object; otherwise, set the list tail pointer
404
if (new_obj->get_next() != 0)
405
new_obj->get_next()->set_prev(new_obj);