Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | 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:
29
//	Zone Memory Allocation. Neat.
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
 
52
#define ZONEID	0x1d4a11
53
 
54
 
55
typedef struct
56
{
57
    // total bytes malloced, including header
58
    int		size;
59
 
60
    // start / end cap for linked list
61
    memblock_t	blocklist;
62
 
63
    memblock_t*	rover;
64
 
65
} memzone_t;
66
 
67
 
68
 
69
memzone_t*	mainzone;
70
 
71
 
72
 
73
//
74
// Z_ClearZone
75
//
76
void Z_ClearZone (memzone_t* zone)
77
{
78
    memblock_t*		block;
79
 
80
    // set the entire zone to one free block
81
    zone->blocklist.next =
82
	zone->blocklist.prev =
83
	block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
84
 
85
    zone->blocklist.user = (void *)zone;
86
    zone->blocklist.tag = PU_STATIC;
87
    zone->rover = block;
88
 
89
    block->prev = block->next = &zone->blocklist;
90
 
91
    // NULL indicates a free block.
92
    block->user = NULL;
93
 
94
    block->size = zone->size - sizeof(memzone_t);
95
}
96
 
97
 
98
 
99
//
100
// Z_Init
101
//
102
void Z_Init (void)
103
{
104
    memblock_t*	block;
105
    int		size;
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 =
112
	mainzone->blocklist.prev =
113
	block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
114
 
115
    mainzone->blocklist.user = (void *)mainzone;
116
    mainzone->blocklist.tag = PU_STATIC;
117
    mainzone->rover = block;
118
 
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
{
133
    memblock_t*		block;
134
    memblock_t*		other;
135
 
136
    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
137
 
138
    if (block->id != ZONEID)
139
	I_Error ("Z_Free: freed a pointer without ZONEID");
140
 
141
    if (block->user > (void **)0x100)
142
    {
143
	// smaller values are not pointers
144
	// Note: OS-dependend?
145
 
146
	// clear the user's mark
147
	*block->user = 0;
148
    }
149
 
150
    // mark as free
151
    block->user = NULL;
152
    block->tag = 0;
153
    block->id = 0;
154
 
155
    other = block->prev;
156
 
157
    if (!other->user)
158
    {
159
	// merge with previous free block
160
	other->size += block->size;
161
	other->next = block->next;
162
	other->next->prev = other;
163
 
164
	if (block == mainzone->rover)
165
	    mainzone->rover = other;
166
 
167
	block = other;
168
    }
169
 
170
    other = block->next;
171
    if (!other->user)
172
    {
173
	// merge the next free block onto the end
174
	block->size += other->size;
175
	block->next = other->next;
176
	block->next->prev = block;
177
 
178
	if (other == mainzone->rover)
179
	    mainzone->rover = block;
180
    }
181
}
182
 
183
 
184
 
185
//
186
// Z_Malloc
187
// You can pass a NULL user if the tag is < PU_PURGELEVEL.
188
//
189
#define MINFRAGMENT		64
190
 
191
 
192
void*
193
Z_Malloc
194
( int		size,
195
  int		tag,
196
  void*		user )
197
{
198
    int		extra;
199
    memblock_t*	start;
200
    memblock_t* rover;
201
    memblock_t* newblock;
202
    memblock_t*	base;
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)
219
	base = base->prev;
220
 
221
    rover = base;
222
    start = base->prev;
223
 
224
    do
225
    {
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)
243
 
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;
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
    {
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;
271
 
272
	base->next = newblock;
273
	base->size = size;
274
    }
275
 
276
    if (user)
277
    {
278
	// mark as an in use block
279
	base->user = user;
280
	*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
281
    }
282
    else
283
    {
284
	if (tag >= PU_PURGELEVEL)
285
	    I_Error ("Z_Malloc: an owner is required for purgable blocks");
286
 
287
	// mark as in use, but unowned
288
	base->user = (void *)2;
289
    }
290
    base->tag = tag;
291
 
292
    // next allocation will start looking here
293
    mainzone->rover = base->next;
294
 
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
307
( int		lowtag,
308
  int		hightag )
309
{
310
    memblock_t*	block;
311
    memblock_t*	next;
312
 
313
    for (block = mainzone->blocklist.next ;
314
	 block != &mainzone->blocklist ;
315
	 block = next)
316
    {
317
	// get link before freeing
318
	next = block->next;
319
 
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));
326
    }
327
}
328
 
329
 
330
 
331
//
332
// Z_DumpHeap
333
// Note: TFileDumpHeap( stdout ) ?
334
//
335
void
336
Z_DumpHeap
337
( int		lowtag,
338
  int		hightag )
339
{
340
    memblock_t*	block;
341
 
342
    printf ("zone size: %i  location: %p\n",
343
	    mainzone->size,mainzone);
344
 
345
    printf ("tag range: %i to %i\n",
346
	    lowtag, hightag);
347
 
348
    for (block = mainzone->blocklist.next ; ; block = block->next)
349
    {
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");
362
 
363
	if ( block->next->prev != block)
364
	    printf ("ERROR: next block doesn't have proper back link\n");
365
 
366
	if (!block->user && !block->next->user)
367
	    printf ("ERROR: two consecutive free blocks\n");
368
    }
369
}
370
 
371
 
372
//
373
// Z_FileDumpHeap
374
//
375
void Z_FileDumpHeap (FILE* f)
376
{
377
    memblock_t*	block;
378
 
379
    fprintf (f,"zone size: %i  location: %p\n",mainzone->size,mainzone);
380
 
381
    for (block = mainzone->blocklist.next ; ; block = block->next)
382
    {
383
	fprintf (f,"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
	    fprintf (f,"ERROR: block size does not touch the next block\n");
394
 
395
	if ( block->next->prev != block)
396
	    fprintf (f,"ERROR: next block doesn't have proper back link\n");
397
 
398
	if (!block->user && !block->next->user)
399
	    fprintf (f,"ERROR: two consecutive free blocks\n");
400
    }
401
}
402
 
403
 
404
 
405
//
406
// Z_CheckHeap
407
//
408
void Z_CheckHeap (void)
409
{
410
    memblock_t*	block;
411
 
412
    for (block = mainzone->blocklist.next ; ; block = block->next)
413
    {
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");
422
 
423
	if ( block->next->prev != block)
424
	    I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
425
 
426
	if (!block->user && !block->next->user)
427
	    I_Error ("Z_CheckHeap: two consecutive free blocks\n");
428
    }
429
}
430
 
431
 
432
 
433
 
434
//
435
// Z_ChangeTag
436
//
437
void
438
Z_ChangeTag2
439
( void*		ptr,
440
  int		tag )
441
{
442
    memblock_t*	block;
443
 
444
    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
445
 
446
    if (block->id != ZONEID)
447
	I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
448
 
449
    if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
450
	I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
451
 
452
    block->tag = tag;
453
}
454
 
455
 
456
 
457
//
458
// Z_FreeMemory
459
//
460
int Z_FreeMemory (void)
461
{
462
    memblock_t*		block;
463
    int			free;
464
 
465
    free = 0;
466
 
467
    for (block = mainzone->blocklist.next ;
468
	 block != &mainzone->blocklist;
469
	 block = block->next)
470
    {
471
	if (!block->user || block->tag >= PU_PURGELEVEL)
472
	    free += block->size;
473
    }
474
    return free;
475
}
476