cfad47cfa3/tads3/vmpoolim.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* 
2
 *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
3
 *   
4
 *   Please see the accompanying license file, LICENSE.TXT, for information
5
 *   on using and copying this software.  
6
 */
7
/*
8
Name
9
  vmpool.cpp - constant pool - in-memory (non-swapping) implementation
10
Function
11
  
12
Notes
13
  
14
Modified
15
  10/20/98 MJRoberts  - Creation
16
*/
17
18
#include <stdlib.h>
19
#include <memory.h>
20
21
#include "t3std.h"
22
#include "vmpool.h"
23
24
25
/* ------------------------------------------------------------------------ */
26
/*
27
 *   In-memory pool implementation.  This pool implementation pre-loads
28
 *   all available pages in the pool and keeps the complete pool in memory
29
 *   at all times. 
30
 */
31
32
/*
33
 *   delete the pool's resources - this is called from our destructor, and
34
 *   can also be called explicitly to reset the pool 
35
 */
36
void CVmPoolInMem::terminate_nv()
37
{
38
    /* free any pages we allocated from the backing store */
39
    free_backing_pages();
40
41
    /* free all of the dynamic object handles */
42
    while (dyn_head_ != 0)
43
    {
44
        CVmPoolDynObj *nxt;
45
46
        /* note the next object */
47
        nxt = dyn_head_->get_next();
48
49
        /* delete this object */
50
        t3free(dyn_head_);
51
52
        /* move on to the next one */
53
        dyn_head_ = nxt;
54
    }
55
56
    /* we no longer have anything in the list */
57
    dyn_head_ = dyn_tail_ = 0;
58
59
    /* we no longer have any dynamic pages */
60
    first_dyn_page_ = 0;
61
}
62
63
/*
64
 *   free pages that we allocated from the backing store 
65
 */
66
void CVmPoolInMem::free_backing_pages()
67
{
68
    size_t i;
69
    pool_ofs_t ofs;
70
    CVmPool_pg *info;
71
72
    /* 
73
     *   delete any dynamically-allocated pages (these are not managed by
74
     *   the backing store) 
75
     */
76
    for (i = first_dyn_page_, info = &pages_[i] ; i < page_slots_ ;
77
         ++i, ++info)
78
    {
79
        /* if this slot was allocated, delete it */
80
        if (info->mem != 0)
81
        {
82
            /* free the memory */
83
            t3free((char *)info->mem);
84
85
            /* note that we've freed it */
86
            info->mem = 0;
87
        }
88
    }
89
90
    /* if there's no backing store, there's nothing to do */
91
    if (backing_store_ == 0)
92
        return;
93
94
    /* 
95
     *   Run through the page array and delete each allocated page.  Since
96
     *   we allocate pages through the backing store, delete pages through
97
     *   the backing store.  
98
     */
99
    for (i = 0, info = pages_, ofs = 0 ; i < first_dyn_page_ ;
100
         ++i, ++info, ofs += page_size_)
101
    {
102
        /* if this slot was allocated, delete it */
103
        if (info->mem != 0)
104
        {
105
            /* delete the page */
106
            backing_store_->vmpbs_free_page(info->mem, ofs, page_size_);
107
108
            /* forget it */
109
            info->mem = 0;
110
        }
111
    }
112
}
113
114
/*
115
 *   initialize 
116
 */
117
void CVmPoolInMem::attach_backing_store(CVmPoolBackingStore *backing_store)
118
{
119
    size_t ofs;
120
    size_t i;
121
    CVmPool_pg *info;
122
    
123
    /* do the normal initialization to allocate the page slots */
124
    CVmPoolPaged::attach_backing_store(backing_store);
125
126
    /* 
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 
129
     */
130
    first_dyn_page_ = page_slots_;
131
132
    /* load all of the pages */
133
    for (i = 0, info = pages_, ofs = 0 ; i < page_slots_ ;
134
         ++i, ++info, ofs += page_size_)
135
    {
136
        size_t load_size;
137
        
138
        /* determine how much memory we really need for this page */
139
        load_size = backing_store_->vmpbs_get_page_size(ofs, page_size_);
140
        
141
        /* allocate and load the page */
142
        info->mem = backing_store_->vmpbs_alloc_and_load_page(
143
            ofs, page_size_, load_size);
144
    }
145
}
146
147
/*
148
 *   Detach from the backing store 
149
 */
150
void CVmPoolInMem::detach_backing_store()
151
{
152
    /* release the backing pages */
153
    free_backing_pages();
154
155
    /* inherit default */
156
    CVmPoolPaged::detach_backing_store();
157
}
158
159
/* ------------------------------------------------------------------------ */
160
/*
161
 *   Dynamic interface implementation 
162
 */
163
164
/*
165
 *   Allocate space in the dynamic pool 
166
 */
167
CVmPoolDynObj *CVmPoolInMem::dynpool_alloc(size_t len)
168
{
169
    CVmPoolDynObj *cur;
170
171
    /* 
172
     *   if the requested size exceeds the page size, we can't allocate
173
     *   it, since each request must fit within a single page 
174
     */
175
    if (len > page_size_)
176
        return 0;
177
    
178
    /*
179
     *   First, see if we can find a free pool object that we've already
180
     *   allocated that will fill the request 
181
     */
182
    for (cur = dyn_head_ ; cur != 0 ; cur = cur->get_next())
183
    {
184
        /* if this object is free, and it's big enough, use it */
185
        if (cur->is_free() && cur->get_len() >= len)
186
        {
187
            /* 
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 
191
             */
192
            if (cur->get_len() > len + 63)
193
            {
194
                CVmPoolDynObj *new_obj;
195
196
                /* 
197
                 *   create a new object, using the space remaining in the
198
                 *   old object after the requested amount of space 
199
                 */
200
                new_obj = new CVmPoolDynObj(cur->get_ofs() + len,
201
                                            cur->get_len() - len);
202
203
                /* reduce the old object to the requested size */
204
                cur->set_len(len);
205
206
                /* link the new object in after the old object */
207
                insert_dyn(cur, new_obj);
208
209
                /* the new object is free */
210
                new_obj->set_free(TRUE);
211
            }
212
213
            /* this object is now in use */
214
            cur->set_free(FALSE);
215
216
            /* return the object we found */
217
            return cur;
218
        }
219
    }
220
221
    /*
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.  
225
     */
226
    alloc_page_slots(page_slots_ + 1);
227
228
    /* allocate space for the page data */
229
    pages_[page_slots_ - 1].mem = (char *)t3malloc(page_size_);
230
231
    /* 
232
     *   if the requested size wouldn't leave much additional space on the
233
     *   page, simply give the entire page to the new object 
234
     */
235
    if (len + 63 >= page_size_)
236
        len = page_size_;
237
238
    /* create a new dynamic pool handle for the new object */
239
    cur = new CVmPoolDynObj(get_page_start_ofs(page_slots_ - 1), len);
240
241
    /* link it in at the end of the list */
242
    append_dyn(cur);
243
244
    /* 
245
     *   if there's any space left over, create yet another object to
246
     *   cover the free space remaining on the page 
247
     */
248
    if (len < page_size_)
249
    {
250
        CVmPoolDynObj *f;
251
        
252
        /* create a new dynamic pool handle for the new object */
253
        f = new CVmPoolDynObj(get_page_start_ofs(page_slots_ - 1) + len,
254
                              page_size_ - len);
255
256
        /* mark it as free */
257
        f->set_free(TRUE);
258
259
        /* link it in at the end of the list */
260
        append_dyn(f);
261
    }
262
263
    /* return the new object */
264
    return cur;
265
}
266
267
/*
268
 *   Delete a dynamic object 
269
 */
270
void CVmPoolInMem::dynpool_delete(CVmPoolDynObj *obj)
271
{
272
    CVmPoolDynObj *cur;
273
    size_t pg;
274
275
    /* mark this object as free */
276
    obj->set_free(TRUE);
277
278
    /* note the page containing this object */
279
    pg = get_page_for_ofs(obj->get_ofs());
280
    
281
    /*
282
     *   Combine this object with any consecutive objects in the same
283
     *   page.  First, look for objects before this object. 
284
     */
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())
289
    {
290
        /* 
291
         *   cur precedes obj, is on the same page, and is also free -
292
         *   combine cur and obj into cur
293
         */
294
        cur->set_len(cur->get_len() + obj->get_len());
295
296
        /* unlink obj from the list, since it's no longer needed */
297
        unlink_dyn(obj);
298
299
        /* delete the original object */
300
        delete obj;
301
302
        /* forget about obj - cur now encompasses it */
303
        obj = cur;
304
    }
305
306
    /*
307
     *   Now combine any consecutive objects that follow 
308
     */
309
    for (cur = obj->get_next() ;
310
         cur != 0 && cur->is_free()
311
             && get_page_for_ofs(cur->get_ofs()) == pg ; )
312
    {
313
        /* 
314
         *   cur follows obj, is on the same page, and is also free -
315
         *   combine cur and obj into obj
316
         */
317
        obj->set_len(obj->get_len() + cur->get_len());
318
319
        /* unlink cur from the list, since it's no longer needed */
320
        unlink_dyn(cur);
321
        
322
        /* delete the second object */
323
        delete cur;
324
325
        /* move on to the next object */
326
        cur = obj->get_next();
327
    }
328
}
329
330
/*
331
 *   Compress the dynamic portion of the pool 
332
 */
333
void CVmPoolInMem::dynpool_compress()
334
{
335
    // $$$
336
}
337
338
/*
339
 *   Append a dynamic handle to the end of our list 
340
 */
341
void CVmPoolInMem::append_dyn(CVmPoolDynObj *obj)
342
{
343
    /* this goes at the end, so there's nothing after this object */
344
    obj->set_next(0);
345
346
    /* the old tail will precede this object in the list */
347
    obj->set_prev(dyn_tail_);
348
349
    /* 
350
     *   if the list is empty, this is the new head; otherwise, set the
351
     *   old tail's forward pointer to the new item 
352
     */
353
    if (dyn_tail_ == 0)
354
        dyn_head_ = obj;
355
    else
356
        dyn_tail_->set_next(obj);
357
358
    /* this is now the tail item */
359
    dyn_tail_ = obj;
360
}
361
362
/*
363
 *   Unlink a dynamic handle from the list 
364
 */
365
void CVmPoolInMem::unlink_dyn(CVmPoolDynObj *obj)
366
{
367
    /* 
368
     *   if there's a previous item, set its forward pointer; otherwise,
369
     *   advance the list head past the item we're unlinking 
370
     */
371
    if (obj->get_prev() != 0)
372
        obj->get_prev()->set_next(obj->get_next());
373
    else
374
        dyn_head_ = obj->get_next();
375
376
    /* 
377
     *   if there's a following item, set its back pointer; otherwise,
378
     *   move the list tail back over the item we're unlinking 
379
     */
380
    if (obj->get_next() != 0)
381
        obj->get_next()->set_prev(obj);
382
    else
383
        dyn_tail_ = obj->get_prev();
384
}
385
386
/*
387
 *   Insert a dynamic handle into the list after the given object
388
 */
389
void CVmPoolInMem::insert_dyn(CVmPoolDynObj *obj, CVmPoolDynObj *new_obj)
390
{
391
    /* the old following object (after obj) will now follow new_obj */
392
    new_obj->set_next(obj->get_next());
393
394
    /* obj will precede new_obj */
395
    new_obj->set_prev(obj);
396
397
    /* new_obj will follow the old object */
398
    obj->set_next(new_obj);
399
400
    /* 
401
     *   if another object follows, set its back pointer to point to the
402
     *   new object; otherwise, set the list tail pointer 
403
     */
404
    if (new_obj->get_next() != 0)
405
        new_obj->get_next()->set_prev(new_obj);
406
    else
407
        dyn_tail_ = new_obj;
408
}