~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads3/vmpoolim.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}