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 */
Z_ClearZone(memzone_t * zone,int size)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 */
Z_Free(void * ptr)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 */
Z_Malloc(int size)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
Z_TagMalloc(int size,int tag)155 void *Z_TagMalloc (int size, int tag)
156 {
157 int extra;
158 memblock_t *start, *rover, *newm, *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 newm = (memblock_t *) ((byte *)base + size );
191 newm->size = extra;
192 newm->tag = 0; // free block
193 newm->prev = base;
194 newm->id = ZONEID;
195 newm->next = base->next;
196 newm->next->prev = newm;
197 base->next = newm;
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 */
Z_Print(memzone_t * zone)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 */
Z_CheckHeap(void)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 */
Hunk_Check(void)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 */
Hunk_Print(qboolean all)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 */
Hunk_AllocName(int size,const char * name)399 void *Hunk_AllocName (int size, const 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 */
Hunk_Alloc(int size)434 void *Hunk_Alloc (int size)
435 {
436 return Hunk_AllocName (size, "unknown");
437 }
438
Hunk_LowMark(void)439 int Hunk_LowMark (void)
440 {
441 return hunk_low_used;
442 }
443
Hunk_FreeToLowMark(int mark)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
Hunk_HighMark(void)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
Hunk_FreeToHighMark(int mark)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 */
Hunk_HighAllocName(int size,const char * name)482 void *Hunk_HighAllocName (int size, const 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 */
Hunk_TempAlloc(int size)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 */
Cache_Move(cache_system_t * c)575 void Cache_Move ( cache_system_t *c)
576 {
577 cache_system_t *newc;
578
579 // we are clearing up space at the bottom, so only allocate it late
580 newc = Cache_TryAlloc (c->size, true);
581 if (newc)
582 {
583 // Con_Printf ("cache_move ok\n");
584
585 Q_memcpy ( newc+1, c+1, c->size - sizeof(cache_system_t) );
586 newc->user = c->user;
587 Q_memcpy (newc->name, c->name, sizeof(newc->name));
588 Cache_Free (c->user);
589 newc->user->data = (void *)(newc+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 */
Cache_FreeLow(int new_low_hunk)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 */
Cache_FreeHigh(int new_high_hunk)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
Cache_UnlinkLRU(cache_system_t * cs)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
Cache_MakeLRU(cache_system_t * cs)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 */
Cache_TryAlloc(int size,qboolean nobottom)680 cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
681 {
682 cache_system_t *cs, *newc;
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 newc = (cache_system_t *) (hunk_base + hunk_low_used);
692 memset (newc, 0, sizeof(*newc));
693 newc->size = size;
694
695 cache_head.prev = cache_head.next = newc;
696 newc->prev = newc->next = &cache_head;
697
698 Cache_MakeLRU (newc);
699 return newc;
700 }
701
702 // search from the bottom up for space
703
704 newc = (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 *)newc >= size)
712 { // found space
713 memset (newc, 0, sizeof(*newc));
714 newc->size = size;
715
716 newc->next = cs;
717 newc->prev = cs->prev;
718 cs->prev->next = newc;
719 cs->prev = newc;
720
721 Cache_MakeLRU (newc);
722
723 return newc;
724 }
725 }
726
727 // continue looking
728 newc = (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 *)newc >= size)
735 {
736 memset (newc, 0, sizeof(*newc));
737 newc->size = size;
738
739 newc->next = &cache_head;
740 newc->prev = cache_head.prev;
741 cache_head.prev->next = newc;
742 cache_head.prev = newc;
743
744 Cache_MakeLRU (newc);
745
746 return newc;
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 */
Cache_Flush(void)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 */
Cache_Print(void)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 */
Cache_Report(void)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 */
Cache_Compact(void)799 void Cache_Compact (void)
800 {
801 }
802
803 /*
804 ============
805 Cache_Init
806
807 ============
808 */
Cache_Init(void)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 */
Cache_Free(cache_user_t * c)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 */
Cache_Check(cache_user_t * c)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 */
Cache_Alloc(cache_user_t * c,int size,const char * name)871 void *Cache_Alloc (cache_user_t *c, int size, const 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 */
Memory_Init(void * buf,int size)913 void Memory_Init (void *buf, int size)
914 {
915 int p;
916 int zonesize = DYNAMIC_SIZE;
917
918 hunk_base = (byte*) 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 = (memzone_t*) Hunk_AllocName (zonesize, "zone" );
933 Z_ClearZone (mainzone, zonesize);
934 }
935
936