Subversion Repositories Kolibri OS

Rev

Rev 298 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
298 serge 1
// Emacs style mode select   -*- C++ -*-
2
//-----------------------------------------------------------------------------
3
//
4
// $Id: z_zone.c,v 1.2 1997/12/29 19:51:30 pekangas Exp $
5
//
6
// Copyright (C) 1993-1996 by id Software, Inc.
7
//
8
// This source is available for distribution and/or modification
9
// only under the terms of the DOOM Source Code License as
10
// published by id Software. All rights reserved.
11
//
12
// The source is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15
// for more details.
16
//
17
// $Log: z_zone.c,v $
18
// Revision 1.2  1997/12/29 19:51:30  pekangas
19
// Ported to WinNT/95 environment using Watcom C 10.6.
20
// Everything expect joystick support is implemented, but networking is
21
// untested. Crashes way too often with problems in FixedDiv().
22
// Compiles with no warnings at warning level 3, uses MIDAS 1.1.1.
23
//
24
// Revision 1.1.1.1  1997/12/28 12:59:07  pekangas
25
// Initial DOOM source release from id Software
26
//
27
//
28
// DESCRIPTION:
333 serge 29
//      Zone Memory Allocation. Neat.
298 serge 30
//
31
//-----------------------------------------------------------------------------
32
 
33
const char
34
z_zone_rcsid[] = "$Id: z_zone.c,v 1.2 1997/12/29 19:51:30 pekangas Exp $";
35
 
36
#include "z_zone.h"
37
#include "i_system.h"
38
#include "doomdef.h"
39
 
40
 
41
//
42
// ZONE MEMORY ALLOCATION
43
//
44
// There is never any space between memblocks,
45
//  and there will never be two contiguous free memblocks.
46
// The rover can be left pointing at a non-empty block.
47
//
48
// It is of no value to free a cachable block,
49
//  because it will get overwritten automatically if needed.
50
//
51
 
333 serge 52
#define ZONEID  0x1d4a11
298 serge 53
 
54
 
55
typedef struct
56
{
57
    // total bytes malloced, including header
333 serge 58
    int         size;
298 serge 59
 
60
    // start / end cap for linked list
333 serge 61
    memblock_t  blocklist;
298 serge 62
 
333 serge 63
    memblock_t* rover;
298 serge 64
 
65
} memzone_t;
66
 
67
 
68
 
333 serge 69
memzone_t*      mainzone;
298 serge 70
 
71
 
72
 
73
//
74
// Z_ClearZone
75
//
76
void Z_ClearZone (memzone_t* zone)
77
{
333 serge 78
    memblock_t*         block;
79
 
298 serge 80
    // set the entire zone to one free block
81
    zone->blocklist.next =
333 serge 82
        zone->blocklist.prev =
83
        block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
298 serge 84
 
85
    zone->blocklist.user = (void *)zone;
86
    zone->blocklist.tag = PU_STATIC;
87
    zone->rover = block;
333 serge 88
 
298 serge 89
    block->prev = block->next = &zone->blocklist;
90
 
91
    // NULL indicates a free block.
333 serge 92
    block->user = NULL;
298 serge 93
 
94
    block->size = zone->size - sizeof(memzone_t);
95
}
96
 
97
 
98
 
99
//
100
// Z_Init
101
//
102
void Z_Init (void)
103
{
333 serge 104
    memblock_t* block;
105
    int         size;
298 serge 106
 
107
    mainzone = (memzone_t *)I_ZoneBase (&size);
108
    mainzone->size = size;
109
 
110
    // set the entire zone to one free block
111
    mainzone->blocklist.next =
333 serge 112
        mainzone->blocklist.prev =
113
        block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
298 serge 114
 
115
    mainzone->blocklist.user = (void *)mainzone;
116
    mainzone->blocklist.tag = PU_STATIC;
117
    mainzone->rover = block;
333 serge 118
 
298 serge 119
    block->prev = block->next = &mainzone->blocklist;
120
 
121
    // NULL indicates a free block.
122
    block->user = NULL;
123
 
124
    block->size = mainzone->size - sizeof(memzone_t);
125
}
126
 
127
 
128
//
129
// Z_Free
130
//
131
void Z_Free (void* ptr)
132
{
333 serge 133
    memblock_t*         block;
134
    memblock_t*         other;
135
 
298 serge 136
    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
137
 
138
    if (block->id != ZONEID)
333 serge 139
        I_Error ("Z_Free: freed a pointer without ZONEID");
140
 
298 serge 141
    if (block->user > (void **)0x100)
142
    {
333 serge 143
        // smaller values are not pointers
144
        // Note: OS-dependend?
145
 
146
        // clear the user's mark
147
        *block->user = 0;
298 serge 148
    }
149
 
150
    // mark as free
333 serge 151
    block->user = NULL;
298 serge 152
    block->tag = 0;
153
    block->id = 0;
333 serge 154
 
298 serge 155
    other = block->prev;
156
 
157
    if (!other->user)
158
    {
333 serge 159
        // merge with previous free block
160
        other->size += block->size;
161
        other->next = block->next;
162
        other->next->prev = other;
298 serge 163
 
333 serge 164
        if (block == mainzone->rover)
165
            mainzone->rover = other;
298 serge 166
 
333 serge 167
        block = other;
298 serge 168
    }
333 serge 169
 
298 serge 170
    other = block->next;
171
    if (!other->user)
172
    {
333 serge 173
        // merge the next free block onto the end
174
        block->size += other->size;
175
        block->next = other->next;
176
        block->next->prev = block;
298 serge 177
 
333 serge 178
        if (other == mainzone->rover)
179
            mainzone->rover = block;
298 serge 180
    }
181
}
182
 
183
 
184
 
185
//
186
// Z_Malloc
187
// You can pass a NULL user if the tag is < PU_PURGELEVEL.
188
//
333 serge 189
#define MINFRAGMENT             64
298 serge 190
 
191
 
192
void*
193
Z_Malloc
333 serge 194
( int           size,
195
  int           tag,
196
  void*         user )
298 serge 197
{
333 serge 198
    int         extra;
199
    memblock_t* start;
298 serge 200
    memblock_t* rover;
201
    memblock_t* newblock;
333 serge 202
    memblock_t* base;
298 serge 203
 
204
    size = (size + 3) & ~3;
205
 
206
    // scan through the block list,
207
    // looking for the first free block
208
    // of sufficient size,
209
    // throwing out any purgable blocks along the way.
210
 
211
    // account for size of block header
212
    size += sizeof(memblock_t);
213
 
214
    // if there is a free block behind the rover,
215
    //  back up over them
216
    base = mainzone->rover;
217
 
218
    if (!base->prev->user)
333 serge 219
        base = base->prev;
220
 
298 serge 221
    rover = base;
222
    start = base->prev;
333 serge 223
 
298 serge 224
    do
225
    {
333 serge 226
        if (rover == start)
227
        {
228
            // scanned all the way around the list
229
            I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
230
        }
231
 
232
        if (rover->user)
233
        {
234
            if (rover->tag < PU_PURGELEVEL)
235
            {
236
                // hit a block that can't be purged,
237
                //  so move base past it
238
                base = rover = rover->next;
239
            }
240
            else
241
            {
242
                // free the rover block (adding the size to base)
298 serge 243
 
333 serge 244
                // the rover can be the base block
245
                base = base->prev;
246
                Z_Free ((byte *)rover+sizeof(memblock_t));
247
                base = base->next;
248
                rover = base->next;
249
            }
250
        }
251
        else
252
            rover = rover->next;
298 serge 253
    } while (base->user || base->size < size);
254
 
255
 
256
    // found a block big enough
257
    extra = base->size - size;
258
 
259
    if (extra >  MINFRAGMENT)
260
    {
333 serge 261
        // there will be a free fragment after the allocated block
262
        newblock = (memblock_t *) ((byte *)base + size );
263
        newblock->size = extra;
264
 
265
        // NULL indicates free block.
266
        newblock->user = NULL;
267
        newblock->tag = 0;
268
        newblock->prev = base;
269
        newblock->next = base->next;
270
        newblock->next->prev = newblock;
298 serge 271
 
333 serge 272
        base->next = newblock;
273
        base->size = size;
298 serge 274
    }
333 serge 275
 
298 serge 276
    if (user)
277
    {
333 serge 278
        // mark as an in use block
279
        base->user = user;
280
        *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
298 serge 281
    }
282
    else
283
    {
333 serge 284
        if (tag >= PU_PURGELEVEL)
285
            I_Error ("Z_Malloc: an owner is required for purgable blocks");
298 serge 286
 
333 serge 287
        // mark as in use, but unowned
288
        base->user = (void *)2;
298 serge 289
    }
290
    base->tag = tag;
291
 
292
    // next allocation will start looking here
333 serge 293
    mainzone->rover = base->next;
294
 
298 serge 295
    base->id = ZONEID;
296
 
297
    return (void *) ((byte *)base + sizeof(memblock_t));
298
}
299
 
300
 
301
 
302
//
303
// Z_FreeTags
304
//
305
void
306
Z_FreeTags
333 serge 307
( int           lowtag,
308
  int           hightag )
298 serge 309
{
333 serge 310
    memblock_t* block;
311
    memblock_t* next;
312
 
298 serge 313
    for (block = mainzone->blocklist.next ;
333 serge 314
         block != &mainzone->blocklist ;
315
         block = next)
298 serge 316
    {
333 serge 317
        // get link before freeing
318
        next = block->next;
298 serge 319
 
333 serge 320
        // free block?
321
        if (!block->user)
322
            continue;
323
 
324
        if (block->tag >= lowtag && block->tag <= hightag)
325
            Z_Free ( (byte *)block+sizeof(memblock_t));
298 serge 326
    }
327
}
328
 
329
 
330
 
331
//
332
// Z_DumpHeap
333
// Note: TFileDumpHeap( stdout ) ?
334
//
335
void
336
Z_DumpHeap
333 serge 337
( int           lowtag,
338
  int           hightag )
298 serge 339
{
333 serge 340
    memblock_t* block;
341
 
342
    //printf ("zone size: %i  location: %p\n",
343
//          mainzone->size,mainzone);
298 serge 344
 
333 serge 345
    //printf ("tag range: %i to %i\n",
346
//          lowtag, hightag);
347
 
298 serge 348
    for (block = mainzone->blocklist.next ; ; block = block->next)
349
    {
333 serge 350
        if (block->tag >= lowtag && block->tag <= hightag)
351
            printf ("block:%p    size:%7i    user:%p    tag:%3i\n",
352
                    block, block->size, block->user, block->tag);
353
 
354
        if (block->next == &mainzone->blocklist)
355
        {
356
            // all blocks have been hit
357
            break;
358
        }
359
 
360
        if ( (byte *)block + block->size != (byte *)block->next)
361
            printf ("ERROR: block size does not touch the next block\n");
298 serge 362
 
333 serge 363
        if ( block->next->prev != block)
364
            printf ("ERROR: next block doesn't have proper back link\n");
298 serge 365
 
333 serge 366
        if (!block->user && !block->next->user)
367
            printf ("ERROR: two consecutive free blocks\n");
298 serge 368
    }
369
}
370
 
371
 
372
//
373
// Z_FileDumpHeap
374
//
375
void Z_FileDumpHeap (FILE* f)
376
{
333 serge 377
    memblock_t* block;
378
 
379
    //printf ("zone size: %i  location: %p\n",mainzone->size,mainzone);
380
 
298 serge 381
    for (block = mainzone->blocklist.next ; ; block = block->next)
382
    {
333 serge 383
        printf ("block:%p    size:%7i    user:%p    tag:%3i\n",
384
                 block, block->size, block->user, block->tag);
385
 
386
        if (block->next == &mainzone->blocklist)
387
        {
388
            // all blocks have been hit
389
            break;
390
        }
391
 
392
        if ( (byte *)block + block->size != (byte *)block->next)
393
            printf ("ERROR: block size does not touch the next block\n");
298 serge 394
 
333 serge 395
        if ( block->next->prev != block)
396
            printf ("ERROR: next block doesn't have proper back link\n");
298 serge 397
 
333 serge 398
        if (!block->user && !block->next->user)
399
            printf ("ERROR: two consecutive free blocks\n");
298 serge 400
    }
401
}
402
 
403
 
404
 
405
//
406
// Z_CheckHeap
407
//
408
void Z_CheckHeap (void)
409
{
333 serge 410
    memblock_t* block;
411
 
298 serge 412
    for (block = mainzone->blocklist.next ; ; block = block->next)
413
    {
333 serge 414
        if (block->next == &mainzone->blocklist)
415
        {
416
            // all blocks have been hit
417
            break;
418
        }
419
 
420
        if ( (byte *)block + block->size != (byte *)block->next)
421
            I_Error ("Z_CheckHeap: block size does not touch the next block\n");
298 serge 422
 
333 serge 423
        if ( block->next->prev != block)
424
            I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
298 serge 425
 
333 serge 426
        if (!block->user && !block->next->user)
427
            I_Error ("Z_CheckHeap: two consecutive free blocks\n");
298 serge 428
    }
429
}
430
 
431
 
432
 
433
 
434
//
435
// Z_ChangeTag
436
//
437
void
438
Z_ChangeTag2
333 serge 439
( void*         ptr,
440
  int           tag )
298 serge 441
{
333 serge 442
    memblock_t* block;
443
 
298 serge 444
    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
445
 
446
    if (block->id != ZONEID)
333 serge 447
        I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
298 serge 448
 
449
    if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
333 serge 450
        I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
298 serge 451
 
452
    block->tag = tag;
453
}
454
 
455
 
456
 
457
//
458
// Z_FreeMemory
459
//
460
int Z_FreeMemory (void)
461
{
333 serge 462
    memblock_t*         block;
463
    int                 free;
464
 
298 serge 465
    free = 0;
466
 
467
    for (block = mainzone->blocklist.next ;
333 serge 468
         block != &mainzone->blocklist;
469
         block = block->next)
298 serge 470
    {
333 serge 471
        if (!block->user || block->tag >= PU_PURGELEVEL)
472
            free += block->size;
298 serge 473
    }
474
    return free;
475
}
476