z_zone.c
上传用户:xuyinpeng
上传日期:2021-05-12
资源大小:455k
文件大小:10k
源码类别:

射击游戏

开发平台:

Visual C++

  1. // Emacs style mode select   -*- C++ -*- 
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  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:$
  18. //
  19. // DESCRIPTION:
  20. // Zone Memory Allocation. Neat.
  21. //
  22. //-----------------------------------------------------------------------------
  23. static const char
  24. rcsid[] = "$Id: z_zone.c,v 1.4 1997/02/03 16:47:58 b1 Exp $";
  25. #include "z_zone.h"
  26. #include "i_system.h"
  27. #include "doomdef.h"
  28. char MsgText[256];
  29. void WriteDebug(char *);
  30. //
  31. // ZONE MEMORY ALLOCATION
  32. //
  33. // There is never any space between memblocks,
  34. //  and there will never be two contiguous free memblocks.
  35. // The rover can be left pointing at a non-empty block.
  36. //
  37. // It is of no value to free a cachable block,
  38. //  because it will get overwritten automatically if needed.
  39. // 
  40.  
  41. #define ZONEID 0x1d4a11
  42. typedef struct
  43. {
  44.     // total bytes malloced, including header
  45.     int size;
  46.     // start / end cap for linked list
  47.     memblock_t blocklist;
  48.     
  49.     memblock_t* rover;
  50.     
  51. } memzone_t;
  52. memzone_t* mainzone;
  53. //
  54. // Z_ClearZone
  55. //
  56. void Z_ClearZone (memzone_t* zone)
  57. {
  58.     memblock_t* block;
  59.     // set the entire zone to one free block
  60.     zone->blocklist.next =
  61. zone->blocklist.prev =
  62. block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
  63.     
  64.     zone->blocklist.user = (void *)zone;
  65.     zone->blocklist.tag = PU_STATIC;
  66.     zone->rover = block;
  67.     block->prev = block->next = &zone->blocklist;
  68.     
  69.     // NULL indicates a free block.
  70.     block->user = NULL;
  71.     block->size = zone->size - sizeof(memzone_t);
  72. }
  73. //
  74. // Z_Init
  75. //
  76. void Z_Init (void)
  77. {
  78.     memblock_t* block;
  79.     int size;
  80.     mainzone = (memzone_t *)I_ZoneBase (&size);
  81.     mainzone->size = size;
  82.     // set the entire zone to one free block
  83.     mainzone->blocklist.next =
  84. mainzone->blocklist.prev =
  85. block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
  86.     mainzone->blocklist.user = (void *)mainzone;
  87.     mainzone->blocklist.tag = PU_STATIC;
  88.     mainzone->rover = block;
  89.     block->prev = block->next = &mainzone->blocklist;
  90.     // NULL indicates a free block.
  91.     block->user = NULL;
  92.     
  93.     block->size = mainzone->size - sizeof(memzone_t);
  94. }
  95. //
  96. // Z_Free
  97. //
  98. void Z_Free (void* ptr)
  99. {
  100.     memblock_t* block;
  101.     memblock_t* other;
  102.     block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  103.     if (block->id != ZONEID)
  104. I_Error ("Z_Free: freed a pointer without ZONEID");
  105.     if (block->user > (void **)0x100)
  106.     {
  107. // smaller values are not pointers
  108. // Note: OS-dependend?
  109. // clear the user's mark
  110. *block->user = 0;
  111.     }
  112.     // mark as free
  113.     block->user = NULL;
  114.     block->tag = 0;
  115.     block->id = 0;
  116.     other = block->prev;
  117.     if (!other->user)
  118.     {
  119. // merge with previous free block
  120. other->size += block->size;
  121. other->next = block->next;
  122. other->next->prev = other;
  123. if (block == mainzone->rover)
  124.     mainzone->rover = other;
  125. block = other;
  126.     }
  127.     other = block->next;
  128.     if (!other->user)
  129.     {
  130. // merge the next free block onto the end
  131. block->size += other->size;
  132. block->next = other->next;
  133. block->next->prev = block;
  134. if (other == mainzone->rover)
  135.     mainzone->rover = block;
  136.     }
  137. }
  138. //
  139. // Z_Malloc
  140. // You can pass a NULL user if the tag is < PU_PURGELEVEL.
  141. //
  142. #define MINFRAGMENT 64
  143. void*
  144. Z_Malloc
  145. ( int size,
  146.   int tag,
  147.   void* user )
  148. {
  149.     int extra;
  150.     memblock_t* start;
  151.     memblock_t* rover;
  152.     memblock_t* newblock;
  153.     memblock_t* base;
  154.     size = (size + 3) & ~3;
  155.     
  156.     // scan through the block list,
  157.     // looking for the first free block
  158.     // of sufficient size,
  159.     // throwing out any purgable blocks along the way.
  160.     // account for size of block header
  161.     size += sizeof(memblock_t);
  162.     
  163.     // if there is a free block behind the rover,
  164.     //  back up over them
  165.     base = mainzone->rover;
  166.     
  167.     if (!base->prev->user)
  168. base = base->prev;
  169.     rover = base;
  170.     start = base->prev;
  171.     do
  172.     {
  173. if (rover == start)
  174. {
  175.     // scanned all the way around the list
  176.     I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
  177. }
  178. if (rover->user)
  179. {
  180.     if (rover->tag < PU_PURGELEVEL)
  181.     {
  182. // hit a block that can't be purged,
  183. //  so move base past it
  184. base = rover = rover->next;
  185.     }
  186.     else
  187.     {
  188. // free the rover block (adding the size to base)
  189. // the rover can be the base block
  190. base = base->prev;
  191. Z_Free ((byte *)rover+sizeof(memblock_t));
  192. base = base->next;
  193. rover = base->next;
  194.     }
  195. }
  196. else
  197.     rover = rover->next;
  198.     } while (base->user || base->size < size);
  199.     
  200.     // found a block big enough
  201.     extra = base->size - size;
  202.     
  203.     if (extra >  MINFRAGMENT)
  204.     {
  205. // there will be a free fragment after the allocated block
  206. newblock = (memblock_t *) ((byte *)base + size );
  207. newblock->size = extra;
  208. // NULL indicates free block.
  209. newblock->user = NULL;
  210. newblock->tag = 0;
  211. newblock->prev = base;
  212. newblock->next = base->next;
  213. newblock->next->prev = newblock;
  214. base->next = newblock;
  215. base->size = size;
  216.     }
  217.     if (user)
  218.     {
  219. // mark as an in use block
  220. base->user = user;
  221. *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
  222.     }
  223.     else
  224.     {
  225. if (tag >= PU_PURGELEVEL)
  226.     I_Error ("Z_Malloc: an owner is required for purgable blocks");
  227. // mark as in use, but unowned
  228. base->user = (void *)2;
  229.     }
  230.     base->tag = tag;
  231.     // next allocation will start looking here
  232.     mainzone->rover = base->next;
  233.     base->id = ZONEID;
  234.     
  235.     return (void *) ((byte *)base + sizeof(memblock_t));
  236. }
  237. //
  238. // Z_FreeTags
  239. //
  240. void
  241. Z_FreeTags
  242. ( int lowtag,
  243.   int hightag )
  244. {
  245.     memblock_t* block;
  246.     memblock_t* next;
  247.     for (block = mainzone->blocklist.next ;
  248.  block != &mainzone->blocklist ;
  249.  block = next)
  250.     {
  251. // get link before freeing
  252. next = block->next;
  253. // free block?
  254. if (!block->user)
  255.     continue;
  256. if (block->tag >= lowtag && block->tag <= hightag)
  257.     Z_Free ( (byte *)block+sizeof(memblock_t));
  258.     }
  259. }
  260. //
  261. // Z_DumpHeap
  262. // Note: TFileDumpHeap( stdout ) ?
  263. //
  264. void
  265. Z_DumpHeap
  266. ( int lowtag,
  267.   int hightag )
  268. {
  269.     memblock_t* block;
  270.     sprintf (MsgText, "zone size: %i  location: %pn",
  271.     mainzone->size,mainzone);
  272.     WriteDebug(MsgText);
  273.     
  274.     sprintf (MsgText,"tag range: %i to %in",
  275.     lowtag, hightag);
  276.     WriteDebug(MsgText);
  277.     for (block = mainzone->blocklist.next ; ; block = block->next)
  278.     {
  279. if (block->tag >= lowtag && block->tag <= hightag)
  280.        {
  281.     sprintf (MsgText,"block:%p    size:%7i    user:%p    tag:%3in",
  282.     block, block->size, block->user, block->tag);
  283.         WriteDebug(MsgText);
  284.        }
  285. if (block->next == &mainzone->blocklist)
  286. {
  287.     // all blocks have been hit
  288.     break;
  289. }
  290. if ( (byte *)block + block->size != (byte *)block->next)
  291.        {
  292.     sprintf(MsgText, "ERROR: block size does not touch the next blockn");
  293.         WriteDebug(MsgText);
  294.        }
  295. if ( block->next->prev != block)
  296.        {
  297.     sprintf(MsgText, "ERROR: next block doesn't have proper back linkn");
  298.         WriteDebug(MsgText);
  299.        }
  300. if (!block->user && !block->next->user)
  301.        {
  302.     sprintf(MsgText, "ERROR: two consecutive free blocksn");
  303.         WriteDebug(MsgText);
  304.        }
  305.     }
  306. }
  307. //
  308. // Z_FileDumpHeap
  309. //
  310. void Z_FileDumpHeap (FILE* f)
  311. {
  312.     memblock_t* block;
  313.     fprintf (f,"zone size: %i  location: %pn",mainzone->size,mainzone);
  314.     for (block = mainzone->blocklist.next ; ; block = block->next)
  315.     {
  316. fprintf (f,"block:%p    size:%7i    user:%p    tag:%3in",
  317.  block, block->size, block->user, block->tag);
  318. if (block->next == &mainzone->blocklist)
  319. {
  320.     // all blocks have been hit
  321.     break;
  322. }
  323. if ( (byte *)block + block->size != (byte *)block->next)
  324.     fprintf (f,"ERROR: block size does not touch the next blockn");
  325. if ( block->next->prev != block)
  326.     fprintf (f,"ERROR: next block doesn't have proper back linkn");
  327. if (!block->user && !block->next->user)
  328.     fprintf (f,"ERROR: two consecutive free blocksn");
  329.     }
  330. }
  331. //
  332. // Z_CheckHeap
  333. //
  334. void Z_CheckHeap (void)
  335. {
  336.     memblock_t* block;
  337.     for (block = mainzone->blocklist.next ; ; block = block->next)
  338.     {
  339. if (block->next == &mainzone->blocklist)
  340. {
  341.     // all blocks have been hit
  342.     break;
  343. }
  344. if ( (byte *)block + block->size != (byte *)block->next)
  345.     I_Error ("Z_CheckHeap: block size does not touch the next blockn");
  346. if ( block->next->prev != block)
  347.     I_Error ("Z_CheckHeap: next block doesn't have proper back linkn");
  348. if (!block->user && !block->next->user)
  349.     I_Error ("Z_CheckHeap: two consecutive free blocksn");
  350.     }
  351. }
  352. //
  353. // Z_ChangeTag
  354. //
  355. void
  356. Z_ChangeTag2
  357. ( void* ptr,
  358.   int tag )
  359. {
  360.     memblock_t* block;
  361.     block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  362.     if (block->id != ZONEID)
  363. I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
  364.     if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
  365. I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
  366.     block->tag = tag;
  367. }
  368. //
  369. // Z_FreeMemory
  370. //
  371. int Z_FreeMemory (void)
  372. {
  373.     memblock_t* block;
  374.     int free;
  375.     free = 0;
  376.     
  377.     for (block = mainzone->blocklist.next ;
  378.  block != &mainzone->blocklist;
  379.  block = block->next)
  380.     {
  381. if (!block->user || block->tag >= PU_PURGELEVEL)
  382.     free += block->size;
  383.     }
  384.     return free;
  385. }