Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
Copyright (C) 1996-1997 Id Software, Inc.
3
 
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
8
 
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
See the GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
 
19
*/
20
// Z_zone.c
21
 
22
#include "quakedef.h"
23
 
24
#define	DYNAMIC_SIZE	0xc000
25
 
26
#define	ZONEID	0x1d4a11
27
#define MINFRAGMENT	64
28
 
29
typedef struct memblock_s
30
{
31
	int		size;           // including the header and possibly tiny fragments
32
	int     tag;            // a tag of 0 is a free block
33
	int     id;        		// should be ZONEID
34
	struct memblock_s       *next, *prev;
35
	int		pad;			// pad to 64 bit boundary
36
} memblock_t;
37
 
38
typedef struct
39
{
40
	int		size;		// total bytes malloced, including header
41
	memblock_t	blocklist;		// start / end cap for linked list
42
	memblock_t	*rover;
43
} memzone_t;
44
 
45
void Cache_FreeLow (int new_low_hunk);
46
void Cache_FreeHigh (int new_high_hunk);
47
 
48
 
49
/*
50
==============================================================================
51
 
52
						ZONE MEMORY ALLOCATION
53
 
54
There is never any space between memblocks, and there will never be two
55
contiguous free memblocks.
56
 
57
The rover can be left pointing at a non-empty block
58
 
59
The zone calls are pretty much only used for small strings and structures,
60
all big things are allocated on the hunk.
61
==============================================================================
62
*/
63
 
64
memzone_t	*mainzone;
65
 
66
void Z_ClearZone (memzone_t *zone, int size);
67
 
68
 
69
/*
70
========================
71
Z_ClearZone
72
========================
73
*/
74
void Z_ClearZone (memzone_t *zone, int size)
75
{
76
	memblock_t	*block;
77
 
78
// set the entire zone to one free block
79
 
80
	zone->blocklist.next = zone->blocklist.prev = block =
81
		(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
82
	zone->blocklist.tag = 1;	// in use block
83
	zone->blocklist.id = 0;
84
	zone->blocklist.size = 0;
85
	zone->rover = block;
86
 
87
	block->prev = block->next = &zone->blocklist;
88
	block->tag = 0;			// free block
89
	block->id = ZONEID;
90
	block->size = size - sizeof(memzone_t);
91
}
92
 
93
 
94
/*
95
========================
96
Z_Free
97
========================
98
*/
99
void Z_Free (void *ptr)
100
{
101
	memblock_t	*block, *other;
102
 
103
	if (!ptr)
104
		Sys_Error ("Z_Free: NULL pointer");
105
 
106
	block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
107
	if (block->id != ZONEID)
108
		Sys_Error ("Z_Free: freed a pointer without ZONEID");
109
	if (block->tag == 0)
110
		Sys_Error ("Z_Free: freed a freed pointer");
111
 
112
	block->tag = 0;		// mark as free
113
 
114
	other = block->prev;
115
	if (!other->tag)
116
	{	// merge with previous free block
117
		other->size += block->size;
118
		other->next = block->next;
119
		other->next->prev = other;
120
		if (block == mainzone->rover)
121
			mainzone->rover = other;
122
		block = other;
123
	}
124
 
125
	other = block->next;
126
	if (!other->tag)
127
	{	// merge the next free block onto the end
128
		block->size += other->size;
129
		block->next = other->next;
130
		block->next->prev = block;
131
		if (other == mainzone->rover)
132
			mainzone->rover = block;
133
	}
134
}
135
 
136
 
137
/*
138
========================
139
Z_Malloc
140
========================
141
*/
142
void *Z_Malloc (int size)
143
{
144
	void	*buf;
145
 
146
Z_CheckHeap ();	// DEBUG
147
	buf = Z_TagMalloc (size, 1);
148
	if (!buf)
149
		Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);
150
	Q_memset (buf, 0, size);
151
 
152
	return buf;
153
}
154
 
155
void *Z_TagMalloc (int size, int tag)
156
{
157
	int		extra;
158
	memblock_t	*start, *rover, *new, *base;
159
 
160
	if (!tag)
161
		Sys_Error ("Z_TagMalloc: tried to use a 0 tag");
162
 
163
//
164
// scan through the block list looking for the first free block
165
// of sufficient size
166
//
167
	size += sizeof(memblock_t);	// account for size of block header
168
	size += 4;					// space for memory trash tester
169
	size = (size + 7) & ~7;		// align to 8-byte boundary
170
 
171
	base = rover = mainzone->rover;
172
	start = base->prev;
173
 
174
	do
175
	{
176
		if (rover == start)	// scaned all the way around the list
177
			return NULL;
178
		if (rover->tag)
179
			base = rover = rover->next;
180
		else
181
			rover = rover->next;
182
	} while (base->tag || base->size < size);
183
 
184
//
185
// found a block big enough
186
//
187
	extra = base->size - size;
188
	if (extra >  MINFRAGMENT)
189
	{	// there will be a free fragment after the allocated block
190
		new = (memblock_t *) ((byte *)base + size );
191
		new->size = extra;
192
		new->tag = 0;			// free block
193
		new->prev = base;
194
		new->id = ZONEID;
195
		new->next = base->next;
196
		new->next->prev = new;
197
		base->next = new;
198
		base->size = size;
199
	}
200
 
201
	base->tag = tag;				// no longer a free block
202
 
203
	mainzone->rover = base->next;	// next allocation will start looking here
204
 
205
	base->id = ZONEID;
206
 
207
// marker for memory trash testing
208
	*(int *)((byte *)base + base->size - 4) = ZONEID;
209
 
210
	return (void *) ((byte *)base + sizeof(memblock_t));
211
}
212
 
213
 
214
/*
215
========================
216
Z_Print
217
========================
218
*/
219
void Z_Print (memzone_t *zone)
220
{
221
	memblock_t	*block;
222
 
223
	Con_Printf ("zone size: %i  location: %p\n",mainzone->size,mainzone);
224
 
225
	for (block = zone->blocklist.next ; ; block = block->next)
226
	{
227
		Con_Printf ("block:%p    size:%7i    tag:%3i\n",
228
			block, block->size, block->tag);
229
 
230
		if (block->next == &zone->blocklist)
231
			break;			// all blocks have been hit
232
		if ( (byte *)block + block->size != (byte *)block->next)
233
			Con_Printf ("ERROR: block size does not touch the next block\n");
234
		if ( block->next->prev != block)
235
			Con_Printf ("ERROR: next block doesn't have proper back link\n");
236
		if (!block->tag && !block->next->tag)
237
			Con_Printf ("ERROR: two consecutive free blocks\n");
238
	}
239
}
240
 
241
 
242
/*
243
========================
244
Z_CheckHeap
245
========================
246
*/
247
void Z_CheckHeap (void)
248
{
249
	memblock_t	*block;
250
 
251
	for (block = mainzone->blocklist.next ; ; block = block->next)
252
	{
253
		if (block->next == &mainzone->blocklist)
254
			break;			// all blocks have been hit
255
		if ( (byte *)block + block->size != (byte *)block->next)
256
			Sys_Error ("Z_CheckHeap: block size does not touch the next block\n");
257
		if ( block->next->prev != block)
258
			Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
259
		if (!block->tag && !block->next->tag)
260
			Sys_Error ("Z_CheckHeap: two consecutive free blocks\n");
261
	}
262
}
263
 
264
//============================================================================
265
 
266
#define	HUNK_SENTINAL	0x1df001ed
267
 
268
typedef struct
269
{
270
	int		sentinal;
271
	int		size;		// including sizeof(hunk_t), -1 = not allocated
272
	char	name[8];
273
} hunk_t;
274
 
275
byte	*hunk_base;
276
int		hunk_size;
277
 
278
int		hunk_low_used;
279
int		hunk_high_used;
280
 
281
qboolean	hunk_tempactive;
282
int		hunk_tempmark;
283
 
284
void R_FreeTextures (void);
285
 
286
/*
287
==============
288
Hunk_Check
289
 
290
Run consistancy and sentinal trahing checks
291
==============
292
*/
293
void Hunk_Check (void)
294
{
295
	hunk_t	*h;
296
 
297
	for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; )
298
	{
299
		if (h->sentinal != HUNK_SENTINAL)
300
			Sys_Error ("Hunk_Check: trahsed sentinal");
301
		if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
302
			Sys_Error ("Hunk_Check: bad size");
303
		h = (hunk_t *)((byte *)h+h->size);
304
	}
305
}
306
 
307
/*
308
==============
309
Hunk_Print
310
 
311
If "all" is specified, every single allocation is printed.
312
Otherwise, allocations with the same name will be totaled up before printing.
313
==============
314
*/
315
void Hunk_Print (qboolean all)
316
{
317
	hunk_t	*h, *next, *endlow, *starthigh, *endhigh;
318
	int		count, sum;
319
	int		totalblocks;
320
	char	name[9];
321
 
322
	name[8] = 0;
323
	count = 0;
324
	sum = 0;
325
	totalblocks = 0;
326
 
327
	h = (hunk_t *)hunk_base;
328
	endlow = (hunk_t *)(hunk_base + hunk_low_used);
329
	starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
330
	endhigh = (hunk_t *)(hunk_base + hunk_size);
331
 
332
	Con_Printf ("          :%8i total hunk size\n", hunk_size);
333
	Con_Printf ("-------------------------\n");
334
 
335
	while (1)
336
	{
337
	//
338
	// skip to the high hunk if done with low hunk
339
	//
340
		if ( h == endlow )
341
		{
342
			Con_Printf ("-------------------------\n");
343
			Con_Printf ("          :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used);
344
			Con_Printf ("-------------------------\n");
345
			h = starthigh;
346
		}
347
 
348
	//
349
	// if totally done, break
350
	//
351
		if ( h == endhigh )
352
			break;
353
 
354
	//
355
	// run consistancy checks
356
	//
357
		if (h->sentinal != HUNK_SENTINAL)
358
			Sys_Error ("Hunk_Check: trahsed sentinal");
359
		if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
360
			Sys_Error ("Hunk_Check: bad size");
361
 
362
		next = (hunk_t *)((byte *)h+h->size);
363
		count++;
364
		totalblocks++;
365
		sum += h->size;
366
 
367
	//
368
	// print the single block
369
	//
370
		memcpy (name, h->name, 8);
371
		if (all)
372
			Con_Printf ("%8p :%8i %8s\n",h, h->size, name);
373
 
374
	//
375
	// print the total
376
	//
377
		if (next == endlow || next == endhigh ||
378
		strncmp (h->name, next->name, 8) )
379
		{
380
			if (!all)
381
				Con_Printf ("          :%8i %8s (TOTAL)\n",sum, name);
382
			count = 0;
383
			sum = 0;
384
		}
385
 
386
		h = next;
387
	}
388
 
389
	Con_Printf ("-------------------------\n");
390
	Con_Printf ("%8i total blocks\n", totalblocks);
391
 
392
}
393
 
394
/*
395
===================
396
Hunk_AllocName
397
===================
398
*/
399
void *Hunk_AllocName (int size, char *name)
400
{
401
	hunk_t	*h;
402
 
403
#ifdef PARANOID
404
	Hunk_Check ();
405
#endif
406
 
407
	if (size < 0)
408
		Sys_Error ("Hunk_Alloc: bad size: %i", size);
409
 
410
	size = sizeof(hunk_t) + ((size+15)&~15);
411
 
412
	if (hunk_size - hunk_low_used - hunk_high_used < size)
413
		Sys_Error ("Hunk_Alloc: failed on %i bytes",size);
414
 
415
	h = (hunk_t *)(hunk_base + hunk_low_used);
416
	hunk_low_used += size;
417
 
418
	Cache_FreeLow (hunk_low_used);
419
 
420
	memset (h, 0, size);
421
 
422
	h->size = size;
423
	h->sentinal = HUNK_SENTINAL;
424
	Q_strncpy (h->name, name, 8);
425
 
426
	return (void *)(h+1);
427
}
428
 
429
/*
430
===================
431
Hunk_Alloc
432
===================
433
*/
434
void *Hunk_Alloc (int size)
435
{
436
	return Hunk_AllocName (size, "unknown");
437
}
438
 
439
int	Hunk_LowMark (void)
440
{
441
	return hunk_low_used;
442
}
443
 
444
void Hunk_FreeToLowMark (int mark)
445
{
446
	if (mark < 0 || mark > hunk_low_used)
447
		Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
448
	memset (hunk_base + mark, 0, hunk_low_used - mark);
449
	hunk_low_used = mark;
450
}
451
 
452
int	Hunk_HighMark (void)
453
{
454
	if (hunk_tempactive)
455
	{
456
		hunk_tempactive = false;
457
		Hunk_FreeToHighMark (hunk_tempmark);
458
	}
459
 
460
	return hunk_high_used;
461
}
462
 
463
void Hunk_FreeToHighMark (int mark)
464
{
465
	if (hunk_tempactive)
466
	{
467
		hunk_tempactive = false;
468
		Hunk_FreeToHighMark (hunk_tempmark);
469
	}
470
	if (mark < 0 || mark > hunk_high_used)
471
		Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
472
	memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
473
	hunk_high_used = mark;
474
}
475
 
476
 
477
/*
478
===================
479
Hunk_HighAllocName
480
===================
481
*/
482
void *Hunk_HighAllocName (int size, char *name)
483
{
484
	hunk_t	*h;
485
 
486
	if (size < 0)
487
		Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
488
 
489
	if (hunk_tempactive)
490
	{
491
		Hunk_FreeToHighMark (hunk_tempmark);
492
		hunk_tempactive = false;
493
	}
494
 
495
#ifdef PARANOID
496
	Hunk_Check ();
497
#endif
498
 
499
	size = sizeof(hunk_t) + ((size+15)&~15);
500
 
501
	if (hunk_size - hunk_low_used - hunk_high_used < size)
502
	{
503
		Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
504
		return NULL;
505
	}
506
 
507
	hunk_high_used += size;
508
	Cache_FreeHigh (hunk_high_used);
509
 
510
	h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
511
 
512
	memset (h, 0, size);
513
	h->size = size;
514
	h->sentinal = HUNK_SENTINAL;
515
	Q_strncpy (h->name, name, 8);
516
 
517
	return (void *)(h+1);
518
}
519
 
520
 
521
/*
522
=================
523
Hunk_TempAlloc
524
 
525
Return space from the top of the hunk
526
=================
527
*/
528
void *Hunk_TempAlloc (int size)
529
{
530
	void	*buf;
531
 
532
	size = (size+15)&~15;
533
 
534
	if (hunk_tempactive)
535
	{
536
		Hunk_FreeToHighMark (hunk_tempmark);
537
		hunk_tempactive = false;
538
	}
539
 
540
	hunk_tempmark = Hunk_HighMark ();
541
 
542
	buf = Hunk_HighAllocName (size, "temp");
543
 
544
	hunk_tempactive = true;
545
 
546
	return buf;
547
}
548
 
549
/*
550
===============================================================================
551
 
552
CACHE MEMORY
553
 
554
===============================================================================
555
*/
556
 
557
typedef struct cache_system_s
558
{
559
	int						size;		// including this header
560
	cache_user_t			*user;
561
	char					name[16];
562
	struct cache_system_s	*prev, *next;
563
	struct cache_system_s	*lru_prev, *lru_next;	// for LRU flushing
564
} cache_system_t;
565
 
566
cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
567
 
568
cache_system_t	cache_head;
569
 
570
/*
571
===========
572
Cache_Move
573
===========
574
*/
575
void Cache_Move ( cache_system_t *c)
576
{
577
	cache_system_t		*new;
578
 
579
// we are clearing up space at the bottom, so only allocate it late
580
	new = Cache_TryAlloc (c->size, true);
581
	if (new)
582
	{
583
//		Con_Printf ("cache_move ok\n");
584
 
585
		Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );
586
		new->user = c->user;
587
		Q_memcpy (new->name, c->name, sizeof(new->name));
588
		Cache_Free (c->user);
589
		new->user->data = (void *)(new+1);
590
	}
591
	else
592
	{
593
//		Con_Printf ("cache_move failed\n");
594
 
595
		Cache_Free (c->user);		// tough luck...
596
	}
597
}
598
 
599
/*
600
============
601
Cache_FreeLow
602
 
603
Throw things out until the hunk can be expanded to the given point
604
============
605
*/
606
void Cache_FreeLow (int new_low_hunk)
607
{
608
	cache_system_t	*c;
609
 
610
	while (1)
611
	{
612
		c = cache_head.next;
613
		if (c == &cache_head)
614
			return;		// nothing in cache at all
615
		if ((byte *)c >= hunk_base + new_low_hunk)
616
			return;		// there is space to grow the hunk
617
		Cache_Move ( c );	// reclaim the space
618
	}
619
}
620
 
621
/*
622
============
623
Cache_FreeHigh
624
 
625
Throw things out until the hunk can be expanded to the given point
626
============
627
*/
628
void Cache_FreeHigh (int new_high_hunk)
629
{
630
	cache_system_t	*c, *prev;
631
 
632
	prev = NULL;
633
	while (1)
634
	{
635
		c = cache_head.prev;
636
		if (c == &cache_head)
637
			return;		// nothing in cache at all
638
		if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
639
			return;		// there is space to grow the hunk
640
		if (c == prev)
641
			Cache_Free (c->user);	// didn't move out of the way
642
		else
643
		{
644
			Cache_Move (c);	// try to move it
645
			prev = c;
646
		}
647
	}
648
}
649
 
650
void Cache_UnlinkLRU (cache_system_t *cs)
651
{
652
	if (!cs->lru_next || !cs->lru_prev)
653
		Sys_Error ("Cache_UnlinkLRU: NULL link");
654
 
655
	cs->lru_next->lru_prev = cs->lru_prev;
656
	cs->lru_prev->lru_next = cs->lru_next;
657
 
658
	cs->lru_prev = cs->lru_next = NULL;
659
}
660
 
661
void Cache_MakeLRU (cache_system_t *cs)
662
{
663
	if (cs->lru_next || cs->lru_prev)
664
		Sys_Error ("Cache_MakeLRU: active link");
665
 
666
	cache_head.lru_next->lru_prev = cs;
667
	cs->lru_next = cache_head.lru_next;
668
	cs->lru_prev = &cache_head;
669
	cache_head.lru_next = cs;
670
}
671
 
672
/*
673
============
674
Cache_TryAlloc
675
 
676
Looks for a free block of memory between the high and low hunk marks
677
Size should already include the header and padding
678
============
679
*/
680
cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
681
{
682
	cache_system_t	*cs, *new;
683
 
684
// is the cache completely empty?
685
 
686
	if (!nobottom && cache_head.prev == &cache_head)
687
	{
688
		if (hunk_size - hunk_high_used - hunk_low_used < size)
689
			Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
690
 
691
		new = (cache_system_t *) (hunk_base + hunk_low_used);
692
		memset (new, 0, sizeof(*new));
693
		new->size = size;
694
 
695
		cache_head.prev = cache_head.next = new;
696
		new->prev = new->next = &cache_head;
697
 
698
		Cache_MakeLRU (new);
699
		return new;
700
	}
701
 
702
// search from the bottom up for space
703
 
704
	new = (cache_system_t *) (hunk_base + hunk_low_used);
705
	cs = cache_head.next;
706
 
707
	do
708
	{
709
		if (!nobottom || cs != cache_head.next)
710
		{
711
			if ( (byte *)cs - (byte *)new >= size)
712
			{	// found space
713
				memset (new, 0, sizeof(*new));
714
				new->size = size;
715
 
716
				new->next = cs;
717
				new->prev = cs->prev;
718
				cs->prev->next = new;
719
				cs->prev = new;
720
 
721
				Cache_MakeLRU (new);
722
 
723
				return new;
724
			}
725
		}
726
 
727
	// continue looking
728
		new = (cache_system_t *)((byte *)cs + cs->size);
729
		cs = cs->next;
730
 
731
	} while (cs != &cache_head);
732
 
733
// try to allocate one at the very end
734
	if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)
735
	{
736
		memset (new, 0, sizeof(*new));
737
		new->size = size;
738
 
739
		new->next = &cache_head;
740
		new->prev = cache_head.prev;
741
		cache_head.prev->next = new;
742
		cache_head.prev = new;
743
 
744
		Cache_MakeLRU (new);
745
 
746
		return new;
747
	}
748
 
749
	return NULL;		// couldn't allocate
750
}
751
 
752
/*
753
============
754
Cache_Flush
755
 
756
Throw everything out, so new data will be demand cached
757
============
758
*/
759
void Cache_Flush (void)
760
{
761
	while (cache_head.next != &cache_head)
762
		Cache_Free ( cache_head.next->user );	// reclaim the space
763
}
764
 
765
 
766
/*
767
============
768
Cache_Print
769
 
770
============
771
*/
772
void Cache_Print (void)
773
{
774
	cache_system_t	*cd;
775
 
776
	for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
777
	{
778
		Con_Printf ("%8i : %s\n", cd->size, cd->name);
779
	}
780
}
781
 
782
/*
783
============
784
Cache_Report
785
 
786
============
787
*/
788
void Cache_Report (void)
789
{
790
	Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
791
}
792
 
793
/*
794
============
795
Cache_Compact
796
 
797
============
798
*/
799
void Cache_Compact (void)
800
{
801
}
802
 
803
/*
804
============
805
Cache_Init
806
 
807
============
808
*/
809
void Cache_Init (void)
810
{
811
	cache_head.next = cache_head.prev = &cache_head;
812
	cache_head.lru_next = cache_head.lru_prev = &cache_head;
813
 
814
	Cmd_AddCommand ("flush", Cache_Flush);
815
}
816
 
817
/*
818
==============
819
Cache_Free
820
 
821
Frees the memory and removes it from the LRU list
822
==============
823
*/
824
void Cache_Free (cache_user_t *c)
825
{
826
	cache_system_t	*cs;
827
 
828
	if (!c->data)
829
		Sys_Error ("Cache_Free: not allocated");
830
 
831
	cs = ((cache_system_t *)c->data) - 1;
832
 
833
	cs->prev->next = cs->next;
834
	cs->next->prev = cs->prev;
835
	cs->next = cs->prev = NULL;
836
 
837
	c->data = NULL;
838
 
839
	Cache_UnlinkLRU (cs);
840
}
841
 
842
 
843
 
844
/*
845
==============
846
Cache_Check
847
==============
848
*/
849
void *Cache_Check (cache_user_t *c)
850
{
851
	cache_system_t	*cs;
852
 
853
	if (!c->data)
854
		return NULL;
855
 
856
	cs = ((cache_system_t *)c->data) - 1;
857
 
858
// move to head of LRU
859
	Cache_UnlinkLRU (cs);
860
	Cache_MakeLRU (cs);
861
 
862
	return c->data;
863
}
864
 
865
 
866
/*
867
==============
868
Cache_Alloc
869
==============
870
*/
871
void *Cache_Alloc (cache_user_t *c, int size, char *name)
872
{
873
	cache_system_t	*cs;
874
 
875
	if (c->data)
876
		Sys_Error ("Cache_Alloc: allready allocated");
877
 
878
	if (size <= 0)
879
		Sys_Error ("Cache_Alloc: size %i", size);
880
 
881
	size = (size + sizeof(cache_system_t) + 15) & ~15;
882
 
883
// find memory for it
884
	while (1)
885
	{
886
		cs = Cache_TryAlloc (size, false);
887
		if (cs)
888
		{
889
			strncpy (cs->name, name, sizeof(cs->name)-1);
890
			c->data = (void *)(cs+1);
891
			cs->user = c;
892
			break;
893
		}
894
 
895
	// free the least recently used cahedat
896
		if (cache_head.lru_prev == &cache_head)
897
			Sys_Error ("Cache_Alloc: out of memory");
898
													// not enough memory at all
899
		Cache_Free ( cache_head.lru_prev->user );
900
	}
901
 
902
	return Cache_Check (c);
903
}
904
 
905
//============================================================================
906
 
907
 
908
/*
909
========================
910
Memory_Init
911
========================
912
*/
913
void Memory_Init (void *buf, int size)
914
{
915
	int p;
916
	int zonesize = DYNAMIC_SIZE;
917
 
918
	hunk_base = buf;
919
	hunk_size = size;
920
	hunk_low_used = 0;
921
	hunk_high_used = 0;
922
 
923
	Cache_Init ();
924
	p = COM_CheckParm ("-zone");
925
	if (p)
926
	{
927
		if (p < com_argc-1)
928
			zonesize = Q_atoi (com_argv[p+1]) * 1024;
929
		else
930
			Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
931
	}
932
	mainzone = Hunk_AllocName (zonesize, "zone" );
933
	Z_ClearZone (mainzone, zonesize);
934
}
935