Subversion Repositories Kolibri OS

Rev

Rev 298 | Blame | Last modification | View Log | Download | RSS feed

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