Esempio n. 1
0
void (Z_Free)(void *p, const char *file, int line)
{
#ifdef INSTRUMENTED
#ifdef CHECKHEAP
  Z_CheckHeap();
#endif
  file_history[free_history][history_index[free_history]] = file;
  line_history[free_history][history_index[free_history]++] = line;
  history_index[free_history] &= ZONE_HISTORY-1;
#endif

  if (p)
    {
      memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE);

#ifdef ZONEIDCHECK
      if (block->id != ZONEID)
        I_Error("Z_Free: freed a pointer without ZONEID\n"
                "Source: %s:%d"

#ifdef INSTRUMENTED
                "\nSource of malloc: %s:%d"
                , file, line, block->file, block->line
#else
                , file, line
#endif
                );
      block->id = 0;              // Nullify id so another free fails
#endif

#ifdef INSTRUMENTED
      // scramble memory -- weed out any bugs
      memset(p, gametic & 0xff, block->size - block->extra);
#endif

      if (block->user)            // Nullify user if one exists
        *block->user = NULL;

      if (block->vm)
        {
          if ((*(memblock_t **) block->prev = block->next))
            block->next->prev = block->prev;

#ifdef INSTRUMENTED
          virtual_memory -= block->size;
#endif
          (free)(block);
        }
      else
        {

#ifdef INSTRUMENTED
          free_memory += block->size;
          inactive_memory -= block->extra;
          if (block->tag >= PU_PURGELEVEL)
            purgable_memory -= block->size - block->extra;
          else
            active_memory -= block->size - block->extra;
#endif

          block->tag = PU_FREE;       // Mark block freed

          if (block != zone)
            {
              other = block->prev;        // Possibly merge with previous block
              if (other->tag == PU_FREE)
                {
                  if (rover == block)  // Move back rover if it points at block
                    rover = other;
                  (other->next = block->next)->prev = other;
                  other->size += block->size + HEADER_SIZE;
                  block = other;

#ifdef INSTRUMENTED
                  inactive_memory -= HEADER_SIZE;
                  free_memory += HEADER_SIZE;
#endif
                }
            }

          other = block->next;        // Possibly merge with next block
          if (other->tag == PU_FREE && other != zone)
            {
              if (rover == other) // Move back rover if it points at next block
                rover = block;
              (block->next = other->next)->prev = block;
              block->size += other->size + HEADER_SIZE;

#ifdef INSTRUMENTED
              inactive_memory -= HEADER_SIZE;
              free_memory += HEADER_SIZE;
#endif
            }
        }

#ifdef INSTRUMENTED
      Z_PrintStats();           // print memory allocation stats
#endif
    }
}
Esempio n. 2
0
void *(Z_Malloc)(size_t size, int tag, void **user, const char *file, int line)
{
  register memblock_t *block;
  memblock_t *start;

#ifdef INSTRUMENTED
  size_t size_orig = size;
#ifdef CHECKHEAP
  Z_CheckHeap();
#endif

  file_history[malloc_history][history_index[malloc_history]] = file;
  line_history[malloc_history][history_index[malloc_history]++] = line;
  history_index[malloc_history] &= ZONE_HISTORY-1;
#endif

#ifdef ZONEIDCHECK
  if (tag >= PU_PURGELEVEL && !user)
    I_Error ("Z_Malloc: an owner is required for purgable blocks\n"
             "Source: %s:%d", file, line);
#endif

  if (!size)
    return user ? *user = NULL : NULL;           // malloc(0) returns NULL

  size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);  // round to chunk size

  block = rover;

  if (block->prev->tag == PU_FREE)
    block = block->prev;

  start = block;

  do
    {
      if (block->tag >= PU_PURGELEVEL)      // Free purgable blocks
        {                                   // replacement is roughly FIFO
          start = block->prev;
          Z_Free((char *) block + HEADER_SIZE);
          block = start = start->next;      // Important: resets start
        }

      if (block->tag == PU_FREE && block->size >= size)   // First-fit
        {
          size_t extra = block->size - size;
          if (extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
            {
              memblock_t *newb = (memblock_t *)((char *) block +
                                                HEADER_SIZE + size);

              (newb->next = block->next)->prev = newb;
              (newb->prev = block)->next = newb;          // Split up block
              block->size = size;
              newb->size = extra - HEADER_SIZE;
              newb->tag = PU_FREE;
              newb->vm = 0;

#ifdef INSTRUMENTED
              inactive_memory += HEADER_SIZE;
              free_memory -= HEADER_SIZE;
#endif
            }

          rover = block->next;           // set roving pointer for next search

#ifdef INSTRUMENTED
          inactive_memory += block->extra = block->size - size_orig;
          if (tag >= PU_PURGELEVEL)
            purgable_memory += size_orig;
          else
            active_memory += size_orig;
          free_memory -= block->size;
#endif

allocated:

#ifdef INSTRUMENTED
          block->file = file;
          block->line = line;
#endif

#ifdef ZONEIDCHECK
          block->id = ZONEID;         // signature required in block header
#endif
          block->tag = tag;           // tag
          block->user = user;         // user
          block = (memblock_t *)((char *) block + HEADER_SIZE);
          if (user)                   // if there is a user
            *user = block;            // set user to point to new block

#ifdef INSTRUMENTED
          Z_PrintStats();           // print memory allocation stats
          // scramble memory -- weed out any bugs
          memset(block, gametic & 0xff, size);
#endif
          return block;
        }
    }
  while ((block = block->next) != start);   // detect cycles as failure

  // We've run out of physical memory, or so we think.
  // Although less efficient, we'll just use ordinary malloc.
  // This will squeeze the remaining juice out of this machine
  // and start cutting into virtual memory if it has it.

  while (!(block = (malloc)(size + HEADER_SIZE)))
    {
      if (!blockbytag[PU_CACHE])
        I_Error ("Z_Malloc: Failure trying to allocate %lu bytes"
                 "\nSource: %s:%d",(unsigned long) size, file, line);
      Z_FreeTags(PU_CACHE,PU_CACHE);
    }

  if ((block->next = blockbytag[tag]))
    block->next->prev = (memblock_t *) &block->next;
  blockbytag[tag] = block;
  block->prev = (memblock_t *) &blockbytag[tag];
  block->vm = 1;

#ifdef INSTRUMENTED
  virtual_memory += 
#endif
    block->size = size + HEADER_SIZE; // CPhipps - this was lost in the #ifdef above

  goto allocated;
}
Esempio n. 3
0
void* (Z_Malloc)(size_t size, int tag, void** user, const char* file, int line)
{
  register memblock_t* block;
  memblock_t* start;

#ifdef INSTRUMENTED
  size_t size_orig = size;
#ifdef CHECKHEAP
  Z_CheckHeap();
#endif

  file_history[malloc_history][history_index[malloc_history]] = file;
  line_history[malloc_history][history_index[malloc_history]++] = line;
  history_index[malloc_history] &= ZONE_HISTORY - 1;
#endif

#ifdef ZONEIDCHECK
  if (tag >= PU_PURGELEVEL && !user)
    I_Error("Z_Malloc: an owner is required for purgable blocks\n"
            "Source: %s:%d", file, line);
#endif

  if (!size)
    return user ? *user = NULL : NULL;           // malloc(0) returns NULL

  size = (size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1); // round to chunk size

  block = rover;

  if (block->prev->tag == PU_FREE)
    block = block->prev;

  start = block;

  // haleyjd 06/17/08: import from EE:
  // the first if() inside the loop below contains cph's memory
  // purging efficiency fix

  do
  {
    // Free purgable blocks; replacement is roughly FIFO
    if (block->tag >= PU_PURGELEVEL)
    {
      start = block->prev;
      Z_Free((char*) block + HEADER_SIZE);
      /* cph - If start->next == block, we did not merge with the previous
       *       If !=, we did, so we continue from start.
       *  Important: we've reset start!
       */
      if (start->next == block)
        start = start->next;
      else
        block = start;
    }

    if (block->tag == PU_FREE && block->size >= size)  // First-fit
    {
      size_t extra = block->size - size;
      if (extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
      {
        memblock_t* newb =
          (memblock_t*)((char*) block + HEADER_SIZE + size);

        (newb->next = block->next)->prev = newb;
        (newb->prev = block)->next = newb;          // Split up block
        block->size = size;
        newb->size = extra - HEADER_SIZE;
        newb->tag = PU_FREE;
        newb->vm = 0;

#ifdef INSTRUMENTED
        inactive_memory += HEADER_SIZE;
        free_memory -= HEADER_SIZE;
#endif
      }

      rover = block->next;           // set roving pointer for next search

#ifdef INSTRUMENTED
      inactive_memory += block->extra = block->size - size_orig;
      if (tag >= PU_PURGELEVEL)
        purgable_memory += size_orig;
      else
        active_memory += size_orig;
      free_memory -= block->size;
#endif

allocated:

#ifdef INSTRUMENTED
      block->file = file;
      block->line = line;
#endif

#ifdef ZONEIDCHECK
      block->id = ZONEID;         // signature required in block header
#endif
      block->tag = tag;           // tag
      block->user = user;         // user
      block = (memblock_t*)((char*) block + HEADER_SIZE);
      if (user)                  // if there is a user
        *user = block;            // set user to point to new block

#ifdef INSTRUMENTED
      Z_PrintStats();           // print memory allocation stats
      // scramble memory -- weed out any bugs
      memset(block, gametic & 0xff, size);
#endif
      return block;
    }
  }
  while ((block = block->next) != start);   // detect cycles as failure

  // We've run out of physical memory, or so we think.
  // Although less efficient, we'll just use ordinary malloc.
  // This will squeeze the remaining juice out of this machine
  // and start cutting into virtual memory if it has it.

  while (!(block = (malloc)(size + HEADER_SIZE)))
  {
    if (!blockbytag[PU_CACHE])
      I_Error("Z_Malloc: Failure trying to allocate %lu bytes"
              "\nSource: %s:%d", (unsigned long) size, file, line);
    Z_FreeTags(PU_CACHE, PU_CACHE);
  }

  if ((block->next = blockbytag[tag]))
    block->next->prev = (memblock_t*) &block->next;
  blockbytag[tag] = block;
  block->prev = (memblock_t*) &blockbytag[tag];
  block->vm = 1;

  // haleyjd: cph's virtual memory error fix
#ifdef INSTRUMENTED
  virtual_memory += size + HEADER_SIZE;

  // haleyjd 06/17/08: Import from EE:
  // Big problem: extra wasn't being initialized for vm
  // blocks. This caused the memset used to randomize freed memory when
  // INSTRUMENTED is defined to stomp all over the C heap.
  block->extra = 0;
#endif
  /* cph - the next line was lost in the #ifdef above, and also added an
   *  extra HEADER_SIZE to block->size, which was incorrect */
  block->size = size;
  goto allocated;
}
Esempio n. 4
0
//
// Z_Realloc
//
// haleyjd 09/18/06: Rewritten to be an actual realloc routine. The
// various cases are as follows:
//
// 1. If the block is NULL, is in virtual memory, or we're trying to set it to
//    zero-byte size, we use Z_ReallocOld above.
// 2. If the block is smaller than the new size, we need to expand it. If the
//    next block on the zone heap is free, check to see if it together with the
//    current block is large enough. If so, merge the blocks. Now test to make
//    sure the internal fragmentation does not exceed the split limit. If it
//    does, resplit the blocks at the new boundary. If the next block wasn't
//    free, we have to call Z_ReallocOld to move the entire block elsewhere.
// 3. If the block is larger than the new size, we can shrink it, but we only
//    need to shrink it if the wasted space is larger than the split limit.
//    If so, the block is split at its new boundary. If the next block on the
//    zone heap is free, it is then necessary to merge the new free block with
//    the next block on the heap. In the event the block is not shrunk, only the
//    INSTRUMENTED data needs to be updated to reflect the new internal fragmen-
//    tation.
// 4. If the block is already the same size as "n", we don't need to do anything
//    aside from adjusting the INSTRUMENTED block data for debugging purposes.
//
void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user, __string file, int line)
{
   register memblock_t __near *block, *other;
   register size_t curr_size = 0;

   // davidph 12/09/12: Handle null and size 0 right here instead of in Z_ReallocOld.
   if(n == 0) { (Z_Free)(ptr, file, line); return NULL; }

   if(!ptr)
      return (Z_Malloc)(n, tag, user, file, line);

   // get current size of block
   block = VoidToBlock(ptr);

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_Realloc: Reallocated a block without ZONEID\n",
             block, file, line);

   other = block->next; // save pointer to next block
   curr_size = block->size;

   // round new size to CHUNK_SIZE
   n = (n + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);

   if(n > curr_size) // is new allocation size larger than current?
   {
      register size_t extra;

      // haleyjd 10/03/06: free adjacent purgable blocks
      while(other != zone && other != block &&
            (other->tag == PU_FREE || other->tag >= PU_PURGELEVEL))
      {
         if(other->tag >= PU_PURGELEVEL)
         {
            (Z_Free)(BlockToVoid(other), file, line);

            // reset pointer to next block
            other = block->next;
         }

         // use current size of block; note it may have increased if it was
         // merged with an adjacent free block

         // if we've freed enough, stop
         if(curr_size + other->size + HEADER_SIZE >= n)
            break;

         // move to next block
         other = other->next;
      }

      // reset pointer
      other = block->next;

      // check to see if it can fit if we merge with the next block
      if(other != zone && other->tag == PU_FREE &&
         curr_size + other->size + HEADER_SIZE >= n)
      {
         // merge the blocks
         if(rover == other)
            rover = block;
         (block->next = other->next)->prev = block;
         block->size += other->size + HEADER_SIZE;

#ifdef INSTRUMENTED
         // lost a block...
         inactive_memory -= HEADER_SIZE;
         // lost a free block...
         free_memory -= other->size;
         // increased active or purgable
         if(block->tag >= PU_PURGELEVEL)
            purgable_memory += other->size + HEADER_SIZE;
         else
            active_memory += other->size + HEADER_SIZE;
#endif

         // check to see if there's enough extra to warrant splitting off
         // a new free block
         extra = block->size - n;

         if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
         {
            register memblock_t __near *newb =
               (memblock_t __near *)((char __near *)block + HEADER_SIZE + n);

            (newb->next = block->next)->prev = newb;
            (newb->prev = block)->next = newb;
            block->size = n;
            newb->size = extra - HEADER_SIZE;
            newb->tag = PU_FREE;

            if(rover == block)
               rover = newb;

#ifdef INSTRUMENTED
            // added a block...
            inactive_memory += HEADER_SIZE;
            // added a free block...
            free_memory += newb->size;
            // decreased active or purgable
            if(block->tag >= PU_PURGELEVEL)
               purgable_memory -= newb->size + HEADER_SIZE;
            else
               active_memory -= newb->size + HEADER_SIZE;
#endif
         }

         // subtract old internal fragmentation and add new
         INSTRUMENT(inactive_memory -= block->extra);
         INSTRUMENT(inactive_memory += (block->extra = block->size - n));
      }
      else // else, do old realloc (make new, copy old, free old)
      {
         // davidph 12/10/12: This was the only place Z_ReallocOld was called.
         //   And we know that ptr != NULL and n != 0 and n > curr_size.

         register void *p = (Z_Malloc)(n, tag, user, file, line);

         memcpy_near((void __near *)p, (void __near *)ptr, curr_size);
         (Z_Free)(ptr, file, line);
         if(user) // in case Z_Free nullified same user
            *user = p;

         return p;
      }
   }
   else if(n < curr_size) // is new allocation size smaller than current?
   {
      // check to see if there's enough extra to warrant splitting off
      // a new free block
      size_t extra = curr_size - n;

      if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
      {
         register memblock_t __near *newb =
            (memblock_t __near *)((char __near *)block + HEADER_SIZE + n);

         (newb->next = block->next)->prev = newb;
         (newb->prev = block)->next = newb;
         block->size = n;
         newb->size = extra - HEADER_SIZE;
         newb->tag = PU_FREE;

#ifdef INSTRUMENTED
         // added a block...
         inactive_memory += HEADER_SIZE;
         // added a free block...
         free_memory += newb->size;
         // decreased purgable or active
         if(block->tag >= PU_PURGELEVEL)
            purgable_memory -= newb->size + HEADER_SIZE;
         else
            active_memory -= newb->size + HEADER_SIZE;
#endif

         // may need to merge new block with next block
         if(other && other->tag == PU_FREE && other != zone)
         {
            if(rover == other) // Move back rover if it points at next block
               rover = newb;
            (newb->next = other->next)->prev = newb;
            newb->size += other->size + HEADER_SIZE;

            // deleted a block...
            INSTRUMENT(inactive_memory -= HEADER_SIZE);
            // space between blocks is now free
            INSTRUMENT(free_memory += HEADER_SIZE);
         }
      }
      // else, leave block the same size

      // subtract old internal fragmentation and add new
      INSTRUMENT(inactive_memory -= block->extra);
      INSTRUMENT(inactive_memory += (block->extra = block->size - n));
   }
   // else new allocation size is same as current, don't change it

   // modify the block
   INSTRUMENT(block->file = file);
   INSTRUMENT(block->line = line);

   // reset ptr for consistency
   ptr = BlockToVoid(block);

   if(block->user != user)
   {
      if(block->user)           // nullify old user if any
         *(block->user) = NULL;
      block->user = user;       // set block's new user
      if(user)                  // if non-null, set user to allocation
         *user = ptr;
   }

   // let Z_ChangeTag handle changing the tag
   if(block->tag != tag)
      (Z_ChangeTag)(ptr, tag, file, line);

   Z_PrintStats();           // print memory allocation stats
   Z_LogPrintf("* Z_Realloc(ptr=%p, n=%u, tag=%d, user=%p, source=%s:%d)\n",
               ptr, n, tag, user, file, line);

   return ptr;
}
Esempio n. 5
0
//
// Z_Free
//
void (Z_Free)(void *p, __string file, int line)
{
   register memblock_t __near *other, *block;

   if(!p) return;

   DEBUG_CHECKHEAP();

   block = VoidToBlock(p);

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_Free: freed a pointer without ZONEID", block, file, line);

   IDCHECK(block->id = 0); // Nullify id so another free fails

   // haleyjd 01/20/09: check invalid tags
   // catches double frees and possible selective heap corruption
   if(block->tag == PU_FREE || block->tag >= PU_MAX)
   {
      zonef("Z_Free: freed a pointer with invalid tag %d\nSource: %s:%d\n"
#ifdef INSTRUMENTED
            "Source of malloc: %s:%d\n"
            , block->tag, file, line, block->file, block->line
#else
            , block->tag, file, line
#endif
            );
      abort();
   }

   SCRAMBLER(p, block->size);

   if(block->user)            // Nullify user if one exists
      *block->user = NULL;

#ifdef INSTRUMENTED
   free_memory += block->size;
   inactive_memory -= block->extra;
   if(block->tag >= PU_PURGELEVEL)
      purgable_memory -= block->size - block->extra;
   else
      active_memory -= block->size - block->extra;
#endif

   block->tag = PU_FREE; // Mark block freed

   if(block != zone)
   {
      other = block->prev; // Possibly merge with previous block
      if(other->tag == PU_FREE)
      {
         if(rover == block)  // Move back rover if it points at block
            rover = other;
         (other->next = block->next)->prev = other;
         other->size += block->size + HEADER_SIZE;
         block = other;

         INSTRUMENT(inactive_memory -= HEADER_SIZE);
         INSTRUMENT(free_memory += HEADER_SIZE);
      }
   }

   other = block->next;        // Possibly merge with next block
   if(other->tag == PU_FREE && other != zone)
   {
      if(rover == other) // Move back rover if it points at next block
         rover = block;
      (block->next = other->next)->prev = block;
      block->size += other->size + HEADER_SIZE;

      INSTRUMENT(inactive_memory -= HEADER_SIZE);
      INSTRUMENT(free_memory += HEADER_SIZE);
   }

   Z_PrintStats(); // print memory allocation stats
   Z_LogPrintf("* Z_Free(p=%p, file=%s:%d)\n", p, file, line);
}
Esempio n. 6
0
//
// Z_Malloc
//
// You can pass a NULL user if the tag is < PU_PURGELEVEL.
//
void *(Z_Malloc)(size_t size, int tag, void **user, __string file, int line)
{
   register memblock_t __near *block, *start;

   INSTRUMENT(register size_t size_orig = size);

   // davidph 12/10/12: If zone not initialized, do so now.
   if(!zone) (Z_Init)(file, line);

   DEBUG_CHECKHEAP();

   Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user),
               "Z_Malloc: an owner is required for purgable blocks",
               file, line);

   if(!size)
      return user ? *user = NULL : NULL;          // malloc(0) returns NULL

   size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);  // round to chunk size

   block = rover;

   if(block->prev->tag == PU_FREE)
      block = block->prev;

   start = block;

   // haleyjd 01/01/01 (happy new year!):
   // the first if() inside the loop below contains cph's memory
   // purging efficiency fix

   do
   {
      // Free purgable blocks; replacement is roughly FIFO
      if(block->tag >= PU_PURGELEVEL)
      {
         start = block->prev;
         Z_Free((char __near *)block + HEADER_SIZE);

         // cph - If start->next == block, we did not merge with the previous
         //       If !=, we did, so we continue from start.
         //  Important: we've reset start!
         if(start->next == block)
            start = start->next;
         else
            block = start;
      }

      if(block->tag == PU_FREE && block->size >= size)   // First-fit
      {
         size_t extra = block->size - size;
         if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
         {
            memblock_t __near *newb = (memblock_t __near *)((char __near *)block + HEADER_SIZE + size);

            (newb->next = block->next)->prev = newb;
            (newb->prev = block)->next = newb;          // Split up block
            block->size = size;
            newb->size = extra - HEADER_SIZE;
            newb->tag = PU_FREE;

            INSTRUMENT(inactive_memory += HEADER_SIZE);
            INSTRUMENT(free_memory -= HEADER_SIZE);
         }

         rover = block->next;           // set roving pointer for next search

#ifdef INSTRUMENTED
         inactive_memory += block->extra = block->size - size_orig;
         if(tag >= PU_PURGELEVEL)
            purgable_memory += size_orig;
         else
            active_memory += size_orig;
         free_memory -= block->size;
#endif

         INSTRUMENT(block->file = file);
         INSTRUMENT(block->line = line);

         IDCHECK(block->id = ZONEID);// signature required in block header
         block->tag = tag;           // tag
         block->user = user;         // user
         block = BlockToVoid(block);
         if(user)                    // if there is a user
            *user = block;           // set user to point to new block

         Z_PrintStats();             // print memory allocation stats

         // scramble memory -- weed out any bugs
         SCRAMBLER(block, size);

         Z_LogPrintf("* %p = Z_Malloc(size=%u, tag=%d, user=%p, source=%s:%d)\n",
                     block, size, tag, user, file, line);

         return block;
      }
   }
   while((block = block->next) != start);   // detect cycles as failure

   zonef("Z_Malloc: Failure trying to allocate %u bytes\nSource: %s:%d\n", size, file, line);
   abort();
}