- int size; // including the header and possibly tiny fragments
- int tag; // a tag of 0 is a free block
- int id; // should be ZONEID
- struct memblock_s *next, *prev;
- int pad; // pad to 64 bit boundary
-} memblock_t;
-
-typedef struct
-{
- int size; // total bytes malloced, including header
- memblock_t blocklist; // start / end cap for linked list
- memblock_t *rover;
-} memzone_t;
-
-void Cache_FreeLow (int new_low_hunk);
-void Cache_FreeHigh (int new_high_hunk);
-
-
-/*
-==============================================================================
-
- ZONE MEMORY ALLOCATION
-
-There is never any space between memblocks, and there will never be two
-contiguous free memblocks.
-
-The rover can be left pointing at a non-empty block
-
-The zone calls are pretty much only used for small strings and structures,
-all big things are allocated on the hunk.
-==============================================================================
-*/
-
-memzone_t *mainzone;
-
-void Z_ClearZone (memzone_t *zone, int size);
-
-
-/*
-========================
-Z_ClearZone
-========================
-*/
-void Z_ClearZone (memzone_t *zone, int size)
-{
- memblock_t *block;
-
-// set the entire zone to one free block
-
- zone->blocklist.next = zone->blocklist.prev = block =
- (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
- zone->blocklist.tag = 1; // in use block
- zone->blocklist.id = 0;
- zone->blocklist.size = 0;
- zone->rover = block;
-
- block->prev = block->next = &zone->blocklist;
- block->tag = 0; // free block
- block->id = ZONEID;
- block->size = size - sizeof(memzone_t);
-}
-
-
-/*
-========================
-Z_Free
-========================
-*/
-void Z_Free (void *ptr)
-{
- memblock_t *block, *other;
-
- if (!ptr)
- Sys_Error ("Z_Free: NULL pointer");
-
- block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
- if (block->id != ZONEID)
- Sys_Error ("Z_Free: freed a pointer without ZONEID");
- if (block->tag == 0)
- Sys_Error ("Z_Free: freed a freed pointer");
-
- block->tag = 0; // mark as free
-
- other = block->prev;
- if (!other->tag)
- { // merge with previous free block
- other->size += block->size;
- other->next = block->next;
- other->next->prev = other;
- if (block == mainzone->rover)
- mainzone->rover = other;
- block = other;
+#if MEMCLUMPING
+ int i, j, k, needed, endbit, largest;
+ memclump_t *clump, **clumpchainpointer;
+#endif
+ memheader_t *mem;
+ if (size <= 0)
+ return NULL;
+ if (pool == NULL)
+ Sys_Error("Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline);
+ if (developer.integer && developer_memory.integer)
+ Con_Printf("Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, size);
+ if (developer.integer && developer_memorydebug.integer)
+ _Mem_CheckSentinelsGlobal(filename, fileline);
+ pool->totalsize += size;
+#if MEMCLUMPING
+ if (size < 4096)
+ {
+ // clumping
+ needed = (sizeof(memheader_t) + size + sizeof(int) + (MEMUNIT - 1)) / MEMUNIT;
+ endbit = MEMBITS - needed;
+ for (clumpchainpointer = &pool->clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
+ {
+ clump = *clumpchainpointer;
+ if (clump->sentinel1 != MEMCLUMP_SENTINEL)
+ Sys_Error("Mem_Alloc: trashed clump sentinel 1 (alloc at %s:%d)", filename, fileline);
+ if (clump->sentinel2 != MEMCLUMP_SENTINEL)
+ Sys_Error("Mem_Alloc: trashed clump sentinel 2 (alloc at %s:%d)", filename, fileline);
+ if (clump->largestavailable >= needed)
+ {
+ largest = 0;
+ for (i = 0;i < endbit;i++)
+ {
+ if (clump->bits[i >> 5] & (1 << (i & 31)))
+ continue;
+ k = i + needed;
+ for (j = i;i < k;i++)
+ if (clump->bits[i >> 5] & (1 << (i & 31)))
+ goto loopcontinue;
+ goto choseclump;
+ loopcontinue:;
+ if (largest < j - i)
+ largest = j - i;
+ }
+ // since clump falsely advertised enough space (nothing wrong
+ // with that), update largest count to avoid wasting time in
+ // later allocations
+ clump->largestavailable = largest;
+ }
+ }
+ pool->realsize += sizeof(memclump_t);
+ clump = malloc(sizeof(memclump_t));
+ if (clump == NULL)
+ Sys_Error("Mem_Alloc: out of memory (alloc at %s:%i)", filename, fileline);
+ memset(clump, 0, sizeof(memclump_t));
+ *clumpchainpointer = clump;
+ clump->sentinel1 = MEMCLUMP_SENTINEL;
+ clump->sentinel2 = MEMCLUMP_SENTINEL;
+ clump->chain = NULL;
+ clump->blocksinuse = 0;
+ clump->largestavailable = MEMBITS - needed;
+ j = 0;
+choseclump:
+ mem = (memheader_t *)((unsigned char *) clump->block + j * MEMUNIT);
+ mem->clump = clump;
+ clump->blocksinuse += needed;
+ for (i = j + needed;j < i;j++)
+ clump->bits[j >> 5] |= (1 << (j & 31));