|
|
1.1 root 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 0x20000
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: #ifdef _WIN32
415: Sys_Error ("Not enough RAM allocated. Try starting using \"-heapsize 16000\" on the QuakeWorld command line.");
416: #else
417: Sys_Error ("Not enough RAM allocated. Try starting using \"-mem 16\" on the QuakeWorld command line.");
418: #endif
419:
420: h = (hunk_t *)(hunk_base + hunk_low_used);
421: hunk_low_used += size;
422:
423: Cache_FreeLow (hunk_low_used);
424:
425: memset (h, 0, size);
426:
427: h->size = size;
428: h->sentinal = HUNK_SENTINAL;
429: Q_strncpy (h->name, name, 8);
430:
431: return (void *)(h+1);
432: }
433:
434: /*
435: ===================
436: Hunk_Alloc
437: ===================
438: */
439: void *Hunk_Alloc (int size)
440: {
441: return Hunk_AllocName (size, "unknown");
442: }
443:
444: int Hunk_LowMark (void)
445: {
446: return hunk_low_used;
447: }
448:
449: void Hunk_FreeToLowMark (int mark)
450: {
451: if (mark < 0 || mark > hunk_low_used)
452: Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
453: memset (hunk_base + mark, 0, hunk_low_used - mark);
454: hunk_low_used = mark;
455: }
456:
457: int Hunk_HighMark (void)
458: {
459: if (hunk_tempactive)
460: {
461: hunk_tempactive = false;
462: Hunk_FreeToHighMark (hunk_tempmark);
463: }
464:
465: return hunk_high_used;
466: }
467:
468: void Hunk_FreeToHighMark (int mark)
469: {
470: if (hunk_tempactive)
471: {
472: hunk_tempactive = false;
473: Hunk_FreeToHighMark (hunk_tempmark);
474: }
475: if (mark < 0 || mark > hunk_high_used)
476: Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
477: memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
478: hunk_high_used = mark;
479: }
480:
481:
482: /*
483: ===================
484: Hunk_HighAllocName
485: ===================
486: */
487: void *Hunk_HighAllocName (int size, char *name)
488: {
489: hunk_t *h;
490:
491: if (size < 0)
492: Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
493:
494: if (hunk_tempactive)
495: {
496: Hunk_FreeToHighMark (hunk_tempmark);
497: hunk_tempactive = false;
498: }
499:
500: #ifdef PARANOID
501: Hunk_Check ();
502: #endif
503:
504: size = sizeof(hunk_t) + ((size+15)&~15);
505:
506: if (hunk_size - hunk_low_used - hunk_high_used < size)
507: {
508: Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
509: return NULL;
510: }
511:
512: hunk_high_used += size;
513: Cache_FreeHigh (hunk_high_used);
514:
515: h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
516:
517: memset (h, 0, size);
518: h->size = size;
519: h->sentinal = HUNK_SENTINAL;
520: Q_strncpy (h->name, name, 8);
521:
522: return (void *)(h+1);
523: }
524:
525:
526: /*
527: =================
528: Hunk_TempAlloc
529:
530: Return space from the top of the hunk
531: =================
532: */
533: void *Hunk_TempAlloc (int size)
534: {
535: void *buf;
536:
537: size = (size+15)&~15;
538:
539: if (hunk_tempactive)
540: {
541: Hunk_FreeToHighMark (hunk_tempmark);
542: hunk_tempactive = false;
543: }
544:
545: hunk_tempmark = Hunk_HighMark ();
546:
547: buf = Hunk_HighAllocName (size, "temp");
548:
549: hunk_tempactive = true;
550:
551: return buf;
552: }
553:
554: /*
555: ===============================================================================
556:
557: CACHE MEMORY
558:
559: ===============================================================================
560: */
561:
562: typedef struct cache_system_s
563: {
564: int size; // including this header
565: cache_user_t *user;
566: char name[16];
567: struct cache_system_s *prev, *next;
568: struct cache_system_s *lru_prev, *lru_next; // for LRU flushing
569: } cache_system_t;
570:
571: cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
572:
573: cache_system_t cache_head;
574:
575: /*
576: ===========
577: Cache_Move
578: ===========
579: */
580: void Cache_Move ( cache_system_t *c)
581: {
582: cache_system_t *new;
583:
584: // we are clearing up space at the bottom, so only allocate it late
585: new = Cache_TryAlloc (c->size, true);
586: if (new)
587: {
588: // Con_Printf ("cache_move ok\n");
589:
590: Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );
591: new->user = c->user;
592: Q_memcpy (new->name, c->name, sizeof(new->name));
593: Cache_Free (c->user);
594: new->user->data = (void *)(new+1);
595: }
596: else
597: {
598: // Con_Printf ("cache_move failed\n");
599:
600: Cache_Free (c->user); // tough luck...
601: }
602: }
603:
604: /*
605: ============
606: Cache_FreeLow
607:
608: Throw things out until the hunk can be expanded to the given point
609: ============
610: */
611: void Cache_FreeLow (int new_low_hunk)
612: {
613: cache_system_t *c;
614:
615: while (1)
616: {
617: c = cache_head.next;
618: if (c == &cache_head)
619: return; // nothing in cache at all
620: if ((byte *)c >= hunk_base + new_low_hunk)
621: return; // there is space to grow the hunk
622: Cache_Move ( c ); // reclaim the space
623: }
624: }
625:
626: /*
627: ============
628: Cache_FreeHigh
629:
630: Throw things out until the hunk can be expanded to the given point
631: ============
632: */
633: void Cache_FreeHigh (int new_high_hunk)
634: {
635: cache_system_t *c, *prev;
636:
637: prev = NULL;
638: while (1)
639: {
640: c = cache_head.prev;
641: if (c == &cache_head)
642: return; // nothing in cache at all
643: if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
644: return; // there is space to grow the hunk
645: if (c == prev)
646: Cache_Free (c->user); // didn't move out of the way
647: else
648: {
649: Cache_Move (c); // try to move it
650: prev = c;
651: }
652: }
653: }
654:
655: void Cache_UnlinkLRU (cache_system_t *cs)
656: {
657: if (!cs->lru_next || !cs->lru_prev)
658: Sys_Error ("Cache_UnlinkLRU: NULL link");
659:
660: cs->lru_next->lru_prev = cs->lru_prev;
661: cs->lru_prev->lru_next = cs->lru_next;
662:
663: cs->lru_prev = cs->lru_next = NULL;
664: }
665:
666: void Cache_MakeLRU (cache_system_t *cs)
667: {
668: if (cs->lru_next || cs->lru_prev)
669: Sys_Error ("Cache_MakeLRU: active link");
670:
671: cache_head.lru_next->lru_prev = cs;
672: cs->lru_next = cache_head.lru_next;
673: cs->lru_prev = &cache_head;
674: cache_head.lru_next = cs;
675: }
676:
677: /*
678: ============
679: Cache_TryAlloc
680:
681: Looks for a free block of memory between the high and low hunk marks
682: Size should already include the header and padding
683: ============
684: */
685: cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
686: {
687: cache_system_t *cs, *new;
688:
689: // is the cache completely empty?
690:
691: if (!nobottom && cache_head.prev == &cache_head)
692: {
693: if (hunk_size - hunk_high_used - hunk_low_used < size)
694: Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
695:
696: new = (cache_system_t *) (hunk_base + hunk_low_used);
697: memset (new, 0, sizeof(*new));
698: new->size = size;
699:
700: cache_head.prev = cache_head.next = new;
701: new->prev = new->next = &cache_head;
702:
703: Cache_MakeLRU (new);
704: return new;
705: }
706:
707: // search from the bottom up for space
708:
709: new = (cache_system_t *) (hunk_base + hunk_low_used);
710: cs = cache_head.next;
711:
712: do
713: {
714: if (!nobottom || cs != cache_head.next)
715: {
716: if ( (byte *)cs - (byte *)new >= size)
717: { // found space
718: memset (new, 0, sizeof(*new));
719: new->size = size;
720:
721: new->next = cs;
722: new->prev = cs->prev;
723: cs->prev->next = new;
724: cs->prev = new;
725:
726: Cache_MakeLRU (new);
727:
728: return new;
729: }
730: }
731:
732: // continue looking
733: new = (cache_system_t *)((byte *)cs + cs->size);
734: cs = cs->next;
735:
736: } while (cs != &cache_head);
737:
738: // try to allocate one at the very end
739: if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)
740: {
741: memset (new, 0, sizeof(*new));
742: new->size = size;
743:
744: new->next = &cache_head;
745: new->prev = cache_head.prev;
746: cache_head.prev->next = new;
747: cache_head.prev = new;
748:
749: Cache_MakeLRU (new);
750:
751: return new;
752: }
753:
754: return NULL; // couldn't allocate
755: }
756:
757: /*
758: ============
759: Cache_Flush
760:
761: Throw everything out, so new data will be demand cached
762: ============
763: */
764: void Cache_Flush (void)
765: {
766: while (cache_head.next != &cache_head)
767: Cache_Free ( cache_head.next->user ); // reclaim the space
768: }
769:
770:
771: /*
772: ============
773: Cache_Print
774:
775: ============
776: */
777: void Cache_Print (void)
778: {
779: cache_system_t *cd;
780:
781: for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
782: {
783: Con_Printf ("%8i : %s\n", cd->size, cd->name);
784: }
785: }
786:
787: /*
788: ============
789: Cache_Report
790:
791: ============
792: */
793: void Cache_Report (void)
794: {
795: Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
796: }
797:
798: /*
799: ============
800: Cache_Compact
801:
802: ============
803: */
804: void Cache_Compact (void)
805: {
806: }
807:
808: /*
809: ============
810: Cache_Init
811:
812: ============
813: */
814: void Cache_Init (void)
815: {
816: cache_head.next = cache_head.prev = &cache_head;
817: cache_head.lru_next = cache_head.lru_prev = &cache_head;
818:
819: Cmd_AddCommand ("flush", Cache_Flush);
820: }
821:
822: /*
823: ==============
824: Cache_Free
825:
826: Frees the memory and removes it from the LRU list
827: ==============
828: */
829: void Cache_Free (cache_user_t *c)
830: {
831: cache_system_t *cs;
832:
833: if (!c->data)
834: Sys_Error ("Cache_Free: not allocated");
835:
836: cs = ((cache_system_t *)c->data) - 1;
837:
838: cs->prev->next = cs->next;
839: cs->next->prev = cs->prev;
840: cs->next = cs->prev = NULL;
841:
842: c->data = NULL;
843:
844: Cache_UnlinkLRU (cs);
845: }
846:
847:
848:
849: /*
850: ==============
851: Cache_Check
852: ==============
853: */
854: void *Cache_Check (cache_user_t *c)
855: {
856: cache_system_t *cs;
857:
858: if (!c->data)
859: return NULL;
860:
861: cs = ((cache_system_t *)c->data) - 1;
862:
863: // move to head of LRU
864: Cache_UnlinkLRU (cs);
865: Cache_MakeLRU (cs);
866:
867: return c->data;
868: }
869:
870:
871: /*
872: ==============
873: Cache_Alloc
874: ==============
875: */
876: void *Cache_Alloc (cache_user_t *c, int size, char *name)
877: {
878: cache_system_t *cs;
879:
880: if (c->data)
881: Sys_Error ("Cache_Alloc: allready allocated");
882:
883: if (size <= 0)
884: Sys_Error ("Cache_Alloc: size %i", size);
885:
886: size = (size + sizeof(cache_system_t) + 15) & ~15;
887:
888: // find memory for it
889: while (1)
890: {
891: cs = Cache_TryAlloc (size, false);
892: if (cs)
893: {
894: strncpy (cs->name, name, sizeof(cs->name)-1);
895: c->data = (void *)(cs+1);
896: cs->user = c;
897: break;
898: }
899:
900: // free the least recently used cahedat
901: if (cache_head.lru_prev == &cache_head)
902: Sys_Error ("Cache_Alloc: out of memory");
903: // not enough memory at all
904: Cache_Free ( cache_head.lru_prev->user );
905: }
906:
907: return Cache_Check (c);
908: }
909:
910: //============================================================================
911:
912:
913: /*
914: ========================
915: Memory_Init
916: ========================
917: */
918: void Memory_Init (void *buf, int size)
919: {
920: int p;
921: int zonesize = DYNAMIC_SIZE;
922:
923: hunk_base = buf;
924: hunk_size = size;
925: hunk_low_used = 0;
926: hunk_high_used = 0;
927:
928: Cache_Init ();
929: p = COM_CheckParm ("-zone");
930: if (p)
931: {
932: if (p < com_argc-1)
933: zonesize = Q_atoi (com_argv[p+1]) * 1024;
934: else
935: Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
936: }
937: mainzone = Hunk_AllocName ( zonesize, "zone" );
938: Z_ClearZone (mainzone, zonesize);
939: }
940:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.