home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -websites- / amidoom / adoom_src-0.7.lha / ADoom_src / z_zone.c < prev    next >
C/C++ Source or Header  |  1997-12-25  |  9KB  |  468 lines

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