Clean up and simplify zone memory allocation

This commit is contained in:
Gustaf Alhäll 2023-07-19 23:17:21 +02:00
parent a752e6c8e4
commit cee5eb47b5
No known key found for this signature in database
GPG key ID: 6C1F67D690CDEDFD

View file

@ -51,27 +51,11 @@ static boolean Z_calloc = false;
//#define ZDEBUG2 //#define ZDEBUG2
#endif #endif
struct memblock_s;
typedef struct
{
struct memblock_s *block; // Describing this memory
UINT32 id; // Should be ZONEID
} ATTRPACK memhdr_t;
// Some code might want aligned memory. Assume it wants memory n bytes
// aligned -- then we allocate n-1 extra bytes and return a pointer to
// the first byte aligned as requested.
// Thus, "real" is the pointer we get from malloc() and will free()
// later, but "hdr" is where the memhdr_t starts.
// For non-aligned allocations they will be the same.
typedef struct memblock_s typedef struct memblock_s
{ {
void *real;
memhdr_t *hdr;
void **user; void **user;
INT32 tag; // purgelevel INT32 tag; // purgelevel
UINT32 id; // Should be ZONEID
size_t size; // including the header and blocks size_t size; // including the header and blocks
size_t realsize; // size of real data only size_t realsize; // size of real data only
@ -82,7 +66,10 @@ typedef struct memblock_s
#endif #endif
struct memblock_s *next, *prev; struct memblock_s *next, *prev;
} ATTRPACK memblock_t; } memblock_t;
#define MEMORY(x) (void *)((uintptr_t)(x) + sizeof(memblock_t))
#define MEMBLOCK(x) (memblock_t *)((uintptr_t)(x) - sizeof(memblock_t))
// both the head and tail of the zone memory block list // both the head and tail of the zone memory block list
static memblock_t head; static memblock_t head;
@ -128,64 +115,6 @@ void Z_Init(void)
// Zone memory allocation // Zone memory allocation
// ---------------------- // ----------------------
/** Returns the corresponding memblock_t for a given memory block.
*
* \param ptr A pointer to allocated memory,
* assumed to have been allocated with Z_Malloc/Z_Calloc.
* \param func A string containing the name of the function that called this,
* to be printed if the function I_Errors
* \return A pointer to the memblock_t for the given memory.
* \sa Z_Free, Z_ReallocAlign
*/
#ifdef ZDEBUG
#define Ptr2Memblock(s, f) Ptr2Memblock2(s, f, __FILE__, __LINE__)
static memblock_t *Ptr2Memblock2(void *ptr, const char* func, const char *file, INT32 line)
#else
static memblock_t *Ptr2Memblock(void *ptr, const char* func)
#endif
{
memhdr_t *hdr;
memblock_t *block;
if (ptr == NULL)
return NULL;
#ifdef ZDEBUG2
CONS_Printf("%s %s:%d\n", func, file, line);
#endif
hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr);
#ifdef VALGRIND_MAKE_MEM_DEFINED
VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
#endif
#ifdef VALGRIND_MEMPOOL_EXISTS
if (!VALGRIND_MEMPOOL_EXISTS(hdr->block))
{
#ifdef ZDEBUG
I_Error("%s: bad memblock from %s:%d", func, file, line);
#else
I_Error("%s: bad memblock", func);
#endif
}
#endif
if (hdr->id != ZONEID)
{
#ifdef ZDEBUG
I_Error("%s: wrong id from %s:%d", func, file, line);
#else
I_Error("%s: wrong id", func);
#endif
}
block = hdr->block;
#ifdef VALGRIND_MAKE_MEM_NOACCESS
VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
#endif
return block;
}
/** Frees allocated memory. /** Frees allocated memory.
* *
* \param ptr A pointer to allocated memory, * \param ptr A pointer to allocated memory,
@ -207,10 +136,14 @@ void Z_Free(void *ptr)
CONS_Debug(DBG_MEMORY, "Z_Free %s:%d\n", file, line); CONS_Debug(DBG_MEMORY, "Z_Free %s:%d\n", file, line);
#endif #endif
block = MEMBLOCK(ptr);
#ifdef PARANOIA
if (block->id != ZONEID)
#ifdef ZDEBUG #ifdef ZDEBUG
block = Ptr2Memblock2(ptr, "Z_Free", file, line); I_Error("Z_Free at %s:%d: wrong id", file, line);
#else #else
block = Ptr2Memblock(ptr, "Z_Free"); I_Error("Z_Free: wrong id");
#endif
#endif #endif
#ifdef ZDEBUG #ifdef ZDEBUG
@ -229,8 +162,6 @@ void Z_Free(void *ptr)
if (block->user != NULL) if (block->user != NULL)
*block->user = NULL; *block->user = NULL;
// Free the memory and get rid of the block.
free(block->real);
#ifdef VALGRIND_DESTROY_MEMPOOL #ifdef VALGRIND_DESTROY_MEMPOOL
VALGRIND_DESTROY_MEMPOOL(block); VALGRIND_DESTROY_MEMPOOL(block);
#endif #endif
@ -287,35 +218,17 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits,
void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
#endif #endif
{ {
I_Assert(alignbits >= 0 && alignbits < (INT32)(sizeof(size_t) * 8));
size_t extrabytes = ((size_t)1<<alignbits) - 1;
size_t padsize = 0;
memblock_t *block; memblock_t *block;
void *ptr; void *ptr;
memhdr_t *hdr; (void)(alignbits); // no longer used, so silence warnings.
void *given;
size_t blocksize = extrabytes + sizeof *hdr + size;
#ifdef ZDEBUG2 #ifdef ZDEBUG2
CONS_Debug(DBG_MEMORY, "Z_Malloc %s:%d\n", file, line); CONS_Debug(DBG_MEMORY, "Z_Malloc %s:%d\n", file, line);
#endif #endif
if (blocksize < size)/* overflow check */ block = xm(sizeof (memblock_t) + size);
I_Error("You are allocating memory too large!"); ptr = MEMORY(block);
I_Assert((intptr_t)ptr % sizeof (void *) == 0);
block = xm(sizeof *block);
#ifdef HAVE_VALGRIND
padsize += (1<<sizeof(size_t))*2;
#endif
ptr = xm(blocksize + padsize*2);
// This horrible calculation makes sure that "given" is aligned
// properly.
given = (void *)((size_t)((UINT8 *)ptr + extrabytes + sizeof *hdr + padsize/2)
& ~extrabytes);
// The mem header lives 'sizeof (memhdr_t)' bytes before given.
hdr = (memhdr_t *)((UINT8 *)given - sizeof *hdr);
#ifdef HAVE_VALGRIND #ifdef HAVE_VALGRIND
Z_calloc = false; Z_calloc = false;
@ -326,41 +239,31 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
head.next = block; head.next = block;
block->next->prev = block; block->next->prev = block;
block->real = ptr;
block->hdr = hdr;
block->tag = tag; block->tag = tag;
block->user = NULL; block->user = NULL;
#ifdef ZDEBUG #ifdef ZDEBUG
block->ownerline = line; block->ownerline = line;
block->ownerfile = file; block->ownerfile = file;
#endif #endif
block->size = blocksize; block->size = sizeof (memblock_t) + size;
block->realsize = size; block->realsize = size;
#ifdef VALGRIND_CREATE_MEMPOOL #ifdef VALGRIND_CREATE_MEMPOOL
VALGRIND_CREATE_MEMPOOL(block, padsize, Z_calloc); VALGRIND_CREATE_MEMPOOL(block, size, Z_calloc);
#endif #endif
//#ifdef VALGRIND_MEMPOOL_ALLOC
// VALGRIND_MEMPOOL_ALLOC(block, hdr, size + sizeof *hdr);
//#endif
hdr->id = ZONEID; block->id = ZONEID;
hdr->block = block;
#ifdef VALGRIND_MAKE_MEM_NOACCESS
VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
#endif
if (user != NULL) if (user != NULL)
{ {
block->user = user; block->user = user;
*(void **)user = given; *(void **)user = ptr;
} }
else if (tag >= PU_PURGELEVEL) else if (tag >= PU_PURGELEVEL)
I_Error("Z_Malloc: attempted to allocate purgable block " I_Error("Z_Malloc: attempted to allocate purgable block "
"(size %s) with no user", sizeu1(size)); "(size %s) with no user", sizeu1(size));
return given; return ptr;
} }
/** The Z_CallocAlign function. /** The Z_CallocAlign function.
@ -437,10 +340,14 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb
#endif #endif
} }
block = MEMBLOCK(ptr);
#ifdef PARANOIA
if (block->id != ZONEID)
#ifdef ZDEBUG #ifdef ZDEBUG
block = Ptr2Memblock2(ptr, "Z_Realloc", file, line); I_Error("Z_ReallocAlign at %s:%d: wrong id", file, line);
#else #else
block = Ptr2Memblock(ptr, "Z_Realloc"); I_Error("Z_ReallocAlign: wrong id");
#endif
#endif #endif
if (block == NULL) if (block == NULL)
@ -491,9 +398,8 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag)
for (block = head.next; block != &head; block = next) for (block = head.next; block != &head; block = next)
{ {
next = block->next; // get link before freeing next = block->next; // get link before freeing
if (block->tag >= lowtag && block->tag <= hightag) if (block->tag >= lowtag && block->tag <= hightag)
Z_Free((UINT8 *)block->hdr + sizeof *block->hdr); Z_Free(MEMORY(block));
} }
} }
@ -516,7 +422,7 @@ void Z_IterateTags(INT32 lowtag, INT32 hightag, boolean (*iterfunc)(void *))
if (block->tag >= lowtag && block->tag <= hightag) if (block->tag >= lowtag && block->tag <= hightag)
{ {
void *mem = (UINT8 *)block->hdr + sizeof *block->hdr; void *mem = MEMORY(block);
boolean free = iterfunc(mem); boolean free = iterfunc(mem);
if (free) if (free)
Z_Free(mem); Z_Free(mem);
@ -561,15 +467,13 @@ void Z_CheckMemCleanup(void)
void Z_CheckHeap(INT32 i) void Z_CheckHeap(INT32 i)
{ {
memblock_t *block; memblock_t *block;
memhdr_t *hdr;
UINT32 blocknumon = 0; UINT32 blocknumon = 0;
void *given; void *given;
for (block = head.next; block != &head; block = block->next) for (block = head.next; block != &head; block = block->next)
{ {
blocknumon++; blocknumon++;
hdr = block->hdr; given = MEMORY(block);
given = (UINT8 *)hdr + sizeof *hdr;
#ifdef ZDEBUG2 #ifdef ZDEBUG2
CONS_Debug(DBG_MEMORY, "block %u owned by %s:%d\n", CONS_Debug(DBG_MEMORY, "block %u owned by %s:%d\n",
blocknumon, block->ownerfile, block->ownerline); blocknumon, block->ownerfile, block->ownerline);
@ -585,7 +489,7 @@ void Z_CheckHeap(INT32 i)
#ifdef ZDEBUG #ifdef ZDEBUG
, block->ownerfile, block->ownerline , block->ownerfile, block->ownerline
#endif #endif
); );
} }
#endif #endif
if (block->user != NULL && *(block->user) != given) if (block->user != NULL && *(block->user) != given)
@ -598,7 +502,7 @@ void Z_CheckHeap(INT32 i)
#ifdef ZDEBUG #ifdef ZDEBUG
, block->ownerfile, block->ownerline , block->ownerfile, block->ownerline
#endif #endif
); );
} }
if (block->next->prev != block) if (block->next->prev != block)
{ {
@ -610,7 +514,7 @@ void Z_CheckHeap(INT32 i)
#ifdef ZDEBUG #ifdef ZDEBUG
, block->ownerfile, block->ownerline , block->ownerfile, block->ownerline
#endif #endif
); );
} }
if (block->prev->next != block) if (block->prev->next != block)
{ {
@ -622,25 +526,9 @@ void Z_CheckHeap(INT32 i)
#ifdef ZDEBUG #ifdef ZDEBUG
, block->ownerfile, block->ownerline , block->ownerfile, block->ownerline
#endif #endif
); );
} }
#ifdef VALGRIND_MAKE_MEM_DEFINED if (block->id != ZONEID)
VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
#endif
if (hdr->block != block)
{
I_Error("Z_CheckHeap %d: block %u"
#ifdef ZDEBUG
"(owned by %s:%d)"
#endif
" doesn't have linkback from allocated memory",
i, blocknumon
#ifdef ZDEBUG
, block->ownerfile, block->ownerline
#endif
);
}
if (hdr->id != ZONEID)
{ {
I_Error("Z_CheckHeap %d: block %u" I_Error("Z_CheckHeap %d: block %u"
#ifdef ZDEBUG #ifdef ZDEBUG
@ -650,11 +538,8 @@ void Z_CheckHeap(INT32 i)
#ifdef ZDEBUG #ifdef ZDEBUG
, block->ownerfile, block->ownerline , block->ownerfile, block->ownerline
#endif #endif
); );
} }
#ifdef VALGRIND_MAKE_MEM_NOACCESS
VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
#endif
} }
} }
@ -676,35 +561,14 @@ void Z_ChangeTag(void *ptr, INT32 tag)
#endif #endif
{ {
memblock_t *block; memblock_t *block;
memhdr_t *hdr;
if (ptr == NULL) if (ptr == NULL)
return; return;
hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr); block = MEMBLOCK(ptr);
#ifdef VALGRIND_MAKE_MEM_DEFINED
VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
#endif
#ifdef VALGRIND_MEMPOOL_EXISTS
if (!VALGRIND_MEMPOOL_EXISTS(hdr->block))
{
#ifdef PARANOIA #ifdef PARANOIA
I_Error("Z_CT at %s:%d: bad memblock", file, line); if (block->id != ZONEID) I_Error("Z_ChangeTag at %s:%d: wrong id", file, line);
#else
I_Error("Z_CT: bad memblock");
#endif
}
#endif
#ifdef PARANOIA
if (hdr->id != ZONEID) I_Error("Z_CT at %s:%d: wrong id", file, line);
#endif
block = hdr->block;
#ifdef VALGRIND_MAKE_MEM_NOACCESS
VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
#endif #endif
if (tag >= PU_PURGELEVEL && block->user == NULL) if (tag >= PU_PURGELEVEL && block->user == NULL)
@ -728,25 +592,14 @@ void Z_SetUser(void *ptr, void **newuser)
#endif #endif
{ {
memblock_t *block; memblock_t *block;
memhdr_t *hdr;
if (ptr == NULL) if (ptr == NULL)
return; return;
hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr); block = MEMBLOCK(ptr);
#ifdef VALGRIND_MAKE_MEM_DEFINED
VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
#endif
#ifdef PARANOIA #ifdef PARANOIA
if (hdr->id != ZONEID) I_Error("Z_CT at %s:%d: wrong id", file, line); if (block->id != ZONEID) I_Error("Z_SetUser at %s:%d: wrong id", file, line);
#endif
block = hdr->block;
#ifdef VALGRIND_MAKE_MEM_NOACCESS
VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
#endif #endif
if (block->tag >= PU_PURGELEVEL && newuser == NULL) if (block->tag >= PU_PURGELEVEL && newuser == NULL)