diff --git a/library/amiga.lib_rev.h b/library/amiga.lib_rev.h index 2e45249..52f4fff 100644 --- a/library/amiga.lib_rev.h +++ b/library/amiga.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "amiga.lib 1.210" -#define VSTRING "amiga.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: amiga.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "amiga.lib 1.211" +#define VSTRING "amiga.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: amiga.lib 1.211 (23.11.2016)" diff --git a/library/amiga.lib_rev.rev b/library/amiga.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/amiga.lib_rev.rev +++ b/library/amiga.lib_rev.rev @@ -1 +1 @@ -210 +211 diff --git a/library/c.lib_rev.h b/library/c.lib_rev.h index ee71f97..27254de 100644 --- a/library/c.lib_rev.h +++ b/library/c.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "c.lib 1.210" -#define VSTRING "c.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: c.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "c.lib 1.211" +#define VSTRING "c.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: c.lib 1.211 (23.11.2016)" diff --git a/library/c.lib_rev.rev b/library/c.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/c.lib_rev.rev +++ b/library/c.lib_rev.rev @@ -1 +1 @@ -210 +211 diff --git a/library/changes b/library/changes index 444d936..96246af 100644 --- a/library/changes +++ b/library/changes @@ -1,3 +1,34 @@ +c.lib 1.211 (23.11.2016) + +- Added more consistency checking to the slab allocator, which is + built if DEBUG is defined in "stdlib_slab.c". + +- Memory allocations are no longer guaranteed to be aligned to + 64 bit word boundaries. In fact, this has not even worked + reliably in the past 10 years. + +- Memory allocation request sizes are now rounded to multiples of + 32 bit words (the size of an address pointer) instead to the + size of a 64 bit word. + +- Reduced the memory footprint of the memory allocation management + data structures by reusing the most significant bit of the + memory allocation size. This allows many more allocations to fit + into the 32 byte chunk slabs, but limits the maximum memory + allocation size to a little less than 2 GBytes. + +- Added integer overflow checks to the memory management code. + +- Reduced the memory management overhead further. This cuts an + additional 8 bytes per allocation, unless neither the slab + allocator nor memory pools are available. With this reduction + the slab allocator is able to use 16 byte chunks, which cover + memory allocation requests of 1..8 bytes. + +- Fixed a bug caused by returning an allocation back to a slab + which passed the wrong pointer. + + c.lib 1.210 (22.11.2016) - Added __get_slab_allocations() function which will report information diff --git a/library/debug.lib_rev.h b/library/debug.lib_rev.h index ea250d1..7d2582c 100644 --- a/library/debug.lib_rev.h +++ b/library/debug.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "debug.lib 1.210" -#define VSTRING "debug.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: debug.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "debug.lib 1.211" +#define VSTRING "debug.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: debug.lib 1.211 (23.11.2016)" diff --git a/library/debug.lib_rev.rev b/library/debug.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/debug.lib_rev.rev +++ b/library/debug.lib_rev.rev @@ -1 +1 @@ -210 +211 diff --git a/library/m.lib_rev.h b/library/m.lib_rev.h index c2a6c66..2c650af 100644 --- a/library/m.lib_rev.h +++ b/library/m.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "m.lib 1.210" -#define VSTRING "m.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: m.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "m.lib 1.211" +#define VSTRING "m.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: m.lib 1.211 (23.11.2016)" diff --git a/library/m.lib_rev.rev b/library/m.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/m.lib_rev.rev +++ b/library/m.lib_rev.rev @@ -1 +1 @@ -210 +211 diff --git a/library/m881.lib_rev.h b/library/m881.lib_rev.h index 7fcf871..7575097 100644 --- a/library/m881.lib_rev.h +++ b/library/m881.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "m881.lib 1.210" -#define VSTRING "m881.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: m881.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "m881.lib 1.211" +#define VSTRING "m881.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: m881.lib 1.211 (23.11.2016)" diff --git a/library/m881.lib_rev.rev b/library/m881.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/m881.lib_rev.rev +++ b/library/m881.lib_rev.rev @@ -1 +1 @@ -210 +211 diff --git a/library/net.lib_rev.h b/library/net.lib_rev.h index c05f5ae..eb63df2 100644 --- a/library/net.lib_rev.h +++ b/library/net.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "net.lib 1.210" -#define VSTRING "net.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: net.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "net.lib 1.211" +#define VSTRING "net.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: net.lib 1.211 (23.11.2016)" diff --git a/library/net.lib_rev.rev b/library/net.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/net.lib_rev.rev +++ b/library/net.lib_rev.rev @@ -1 +1 @@ -210 +211 diff --git a/library/stdlib_free.c b/library/stdlib_free.c index 2992406..5bac7cb 100644 --- a/library/stdlib_free.c +++ b/library/stdlib_free.c @@ -31,6 +31,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/*#define DEBUG*/ + #ifndef _STDLIB_HEADERS_H #include "stdlib_headers.h" #endif /* _STDLIB_HEADERS_H */ @@ -165,7 +167,7 @@ dump_memory(unsigned char * m,int size,int ignore) STATIC VOID check_memory_node(struct MemoryNode * mn,const char * file,int line) { - size_t size = mn->mn_Size; + ULONG size = GET_MN_SIZE(mn); unsigned char * head = (unsigned char *)(mn + 1); unsigned char * body = head + MALLOC_HEAD_SIZE; unsigned char * tail = body + size; @@ -227,10 +229,12 @@ check_memory_node(struct MemoryNode * mn,const char * file,int line) if(mn->mn_AlreadyFree) { - for(i = 0 ; i < size ; i++) + ULONG j; + + for(j = 0 ; j < size ; j++) { - if(body[i] != MALLOC_FREE_FILL) - max_body_damage = i+1; + if(body[j] != MALLOC_FREE_FILL) + max_body_damage = j+1; } if(max_body_damage > 0) @@ -345,17 +349,17 @@ remove_and_free_memory_node(struct MemoryNode * mn) __memory_lock(); - Remove((struct Node *)mn); - - #if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG) + #if defined(__MEM_DEBUG) { - __red_black_tree_remove(&__memory_tree,mn); - } - #endif /* __USE_MEM_TREES && __MEM_DEBUG */ + Remove((struct Node *)mn); - #ifdef __MEM_DEBUG - { - allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + mn->mn_Size + MALLOC_TAIL_SIZE; + #if defined(__USE_MEM_TREES) + { + __red_black_tree_remove(&__memory_tree,mn); + } + #endif /* __USE_MEM_TREES */ + + allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + GET_MN_SIZE(mn) + MALLOC_TAIL_SIZE; assert( allocation_size == mn->mn_AllocationSize ); @@ -363,7 +367,7 @@ remove_and_free_memory_node(struct MemoryNode * mn) } #else { - allocation_size = sizeof(*mn) + mn->mn_Size; + allocation_size = sizeof(*mn) + GET_MN_SIZE(mn); } #endif /* __MEM_DEBUG */ @@ -371,18 +375,56 @@ remove_and_free_memory_node(struct MemoryNode * mn) { /* Are we using the slab allocator? */ if (__slab_data.sd_InUse) + { __slab_free(mn,allocation_size); + } else if (__memory_pool != NULL) + { FreePooled(__memory_pool,mn,allocation_size); + } else - FreeMem(mn,allocation_size); + { + #if defined(__MEM_DEBUG) + { + FreeMem(mn,allocation_size); + } + #else + { + struct MinNode * mln = (struct MinNode *)mn; + + mln--; + + Remove((struct Node *)mln); + + FreeMem(mln,sizeof(*mln) + allocation_size); + } + #endif /* __MEM_DEBUG */ + } } #else { if (__memory_pool != NULL) + { FreePooled(__memory_pool,mn,allocation_size); + } else - FreeMem(mn,allocation_size); + { + #if defined(__MEM_DEBUG) + { + FreeMem(mn,allocation_size); + } + #else + { + struct MinNode * mln = (struct MinNode *)mn; + + mln--; + + Remove((struct Node *)mln); + + FreeMem(mln,sizeof(*mln) + allocation_size); + } + #endif /* __MEM_DEBUG */ + } } #endif /* __USE_SLAB_ALLOCATOR */ @@ -401,7 +443,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li #ifdef __MEM_DEBUG { - size_t size = mn->mn_Size; + ULONG size = GET_MN_SIZE(mn); check_memory_node(mn,file,line); @@ -409,7 +451,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li { #ifdef __MEM_DEBUG_LOG { - kprintf("[%s] - %10ld 0x%08lx [",__program_name,mn->mn_Size,mn->mn_Allocation); + kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation); if(mn->mn_File != NULL) kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line); @@ -436,14 +478,14 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li { #ifdef __MEM_DEBUG_LOG { - kprintf("[%s] - %10ld 0x%08lx [",__program_name,mn->mn_Size,mn->mn_Allocation); + kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation); kprintf("FAILED]\n"); } #endif /* __MEM_DEBUG_LOG */ kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld", - __program_name,file,line,mn->mn_Allocation,mn->mn_Size); + __program_name,file,line,mn->mn_Allocation,size); if(mn->mn_File != NULL) kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line); @@ -467,6 +509,9 @@ __free_memory(void * ptr,BOOL force,const char * file,int line) assert(ptr != NULL); + SHOWPOINTER(ptr); + SHOWVALUE(force); + #ifdef __MEM_DEBUG { /*if((rand() % 16) == 0) @@ -480,7 +525,7 @@ __free_memory(void * ptr,BOOL force,const char * file,int line) { if(mn != NULL) { - if(force || (NOT mn->mn_NeverFree)) + if(force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE)) __free_memory_node(mn,file,line); } else @@ -502,7 +547,9 @@ __free_memory(void * ptr,BOOL force,const char * file,int line) { assert( mn != NULL ); - if(mn != NULL && (force || (NOT mn->mn_NeverFree))) + SHOWVALUE(mn->mn_Size); + + if(mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE))) __free_memory_node(mn,file,line); } #endif /* __MEM_DEBUG */ diff --git a/library/stdlib_malloc.c b/library/stdlib_malloc.c index 22988d5..1c1987f 100644 --- a/library/stdlib_malloc.c +++ b/library/stdlib_malloc.c @@ -31,6 +31,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/*#define DEBUG*/ + #ifndef _STDLIB_HEADERS_H #include "stdlib_headers.h" #endif /* _STDLIB_HEADERS_H */ @@ -72,25 +74,6 @@ struct MinList NOCOMMON __memory_list; /****************************************************************************/ -size_t -__get_allocation_size(size_t size) -{ - #ifndef __MEM_DEBUG - { - size_t total_allocation_size; - - total_allocation_size = sizeof(struct MemoryNode) + size; - - /* Round up the allocation size to the physical allocation granularity. */ - size += ((total_allocation_size + MEM_BLOCKMASK) & ~((ULONG)MEM_BLOCKMASK)) - total_allocation_size; - } - #endif /* __MEM_DEBUG */ - - return(size); -} - -/****************************************************************************/ - void * __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_name,int UNUSED debug_line_number) { @@ -135,13 +118,32 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam } #else { - /* Round up the allocation size to the physical allocation granularity. */ - size = __get_allocation_size(size); + /* Round up allocation to a multiple of 32 bits. */ + if((size & 3) != 0) + size += 4 - (size & 3); allocation_size = sizeof(*mn) + size; } #endif /* __MEM_DEBUG */ + /* Integer overflow has occured? */ + if(size == 0 || allocation_size < size) + { + __set_errno(ENOMEM); + goto out; + } + + /* We reuse the MemoryNode.mn_Size field to mark + * allocations are not suitable for use with + * free() and realloc(). This limits allocation + * sizes to a little less than 2 GBytes. + */ + if(allocation_size & MN_SIZE_NEVERFREE) + { + __set_errno(ENOMEM); + goto out; + } + #if defined(__USE_SLAB_ALLOCATOR) { /* Are we using the slab allocator? */ @@ -155,15 +157,27 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam } else { - #if defined(__amigaos4__) - { - mn = AllocMem(allocation_size,MEMF_PRIVATE); - } - #else + #ifdef __MEM_DEBUG { mn = AllocMem(allocation_size,MEMF_ANY); } - #endif /* __amigaos4__ */ + #else + { + struct MinNode * mln; + + mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY); + if(mln != NULL) + { + AddTail((struct List *)&__memory_list,(struct Node *)mln); + + mn = (struct MemoryNode *)&mln[1]; + } + else + { + mn = NULL; + } + } + #endif /* __MEM_DEBUG */ } } #else @@ -174,15 +188,27 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam } else { - #if defined(__amigaos4__) - { - mn = AllocMem(allocation_size,MEMF_PRIVATE); - } - #else + #ifdef __MEM_DEBUG { mn = AllocMem(allocation_size,MEMF_ANY); } - #endif /* __amigaos4__ */ + #else + { + struct MinNode * mln; + + mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY); + if(mln != NULL) + { + AddTail((struct List *)&__memory_list,(struct Node *)mln); + + mn = (struct MemoryNode *)&mln[1]; + } + else + { + mn = NULL; + } + } + #endif /* __MEM_DEBUG */ } } #endif /* __USE_SLAB_ALLOCATOR */ @@ -193,10 +219,10 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam goto out; } - mn->mn_Size = size; - mn->mn_NeverFree = never_free; + mn->mn_Size = size; - AddTail((struct List *)&__memory_list,(struct Node *)mn); + if(never_free) + SET_FLAG(mn->mn_Size, MN_SIZE_NEVERFREE); __current_memory_allocated += allocation_size; if(__maximum_memory_allocated < __current_memory_allocated) @@ -212,6 +238,8 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam char * body = head + MALLOC_HEAD_SIZE; char * tail = body + size; + AddTail((struct List *)&__memory_list,(struct Node *)mn); + mn->mn_AlreadyFree = FALSE; mn->mn_Allocation = body; mn->mn_AllocationSize = allocation_size; diff --git a/library/stdlib_memory.h b/library/stdlib_memory.h index 7bb7e9a..c27ef9a 100644 --- a/library/stdlib_memory.h +++ b/library/stdlib_memory.h @@ -124,7 +124,6 @@ #define __find_memory_node __find_memory_node_debug #define __free_memory_node __free_memory_node_debug -#define __get_allocation_size __get_allocation_size_debug #define __allocate_memory __allocate_memory_debug #define __memory_pool __memory_pool_debug @@ -151,16 +150,24 @@ extern char * __getcwd(char * buffer,size_t buffer_size,const char *file,int lin /****************************************************************************/ +/* If this flag is set in mn_Size, then this memory allocation + * cannot be released with free() or used with realloc(). This + * flag is set by alloca(). + */ +#define MN_SIZE_NEVERFREE (0x80000000UL) + +/* This obtains the allocation size from a memory node, ignoring + * the "never free" flag altogether. + */ +#define GET_MN_SIZE(mn) ((mn)->mn_Size & ~MN_SIZE_NEVERFREE) + struct MemoryNode { - struct MinNode mn_MinNode; - size_t mn_Size; - - UBYTE mn_NeverFree; - #ifdef __MEM_DEBUG + struct MinNode mn_MinNode; + UBYTE mn_AlreadyFree; - UBYTE mn_Pad0[2]; + UBYTE mn_Pad0[3]; void * mn_Allocation; size_t mn_AllocationSize; @@ -179,9 +186,9 @@ struct MemoryNode UBYTE mn_Pad1[3]; #endif /* __USE_MEM_TREES */ -#else - UBYTE mn_Pad0[3]; #endif /* __MEM_DEBUG */ + + ULONG mn_Size; }; #ifdef __USE_MEM_TREES diff --git a/library/stdlib_slab.c b/library/stdlib_slab.c index 460eff2..f0837bc 100644 --- a/library/stdlib_slab.c +++ b/library/stdlib_slab.c @@ -59,42 +59,57 @@ __slab_allocate(size_t allocation_size) { struct SlabChunk * chunk; void * allocation = NULL; + size_t allocation_size_with_chunk_header; D(("allocating %lu bytes of memory",allocation_size)); assert( __slab_data.sd_StandardSlabSize > 0 ); + /* Check for integer overflow. */ + allocation_size_with_chunk_header = sizeof(*chunk) + allocation_size; + if(allocation_size_with_chunk_header < allocation_size) + return(NULL); + /* Number of bytes to allocate exceeds the slab size? * If so, allocate this memory chunk separately and * keep track of it. */ - if(allocation_size + sizeof(*chunk) > __slab_data.sd_StandardSlabSize) + if(allocation_size_with_chunk_header > __slab_data.sd_StandardSlabSize) { - struct SlabSingleAllocation * single_allocation; - ULONG total_single_allocation_size = sizeof(*single_allocation) + allocation_size; + struct SlabSingleAllocation * ssa; + ULONG total_single_allocation_size = sizeof(*ssa) + allocation_size; D(("allocation size is > %ld; this will be stored separately",__slab_data.sd_StandardSlabSize)); - D(("allocating %ld (MinNode+Size) + %ld = %ld bytes",sizeof(*single_allocation),allocation_size,total_single_allocation_size)); + D(("allocating %ld (MinNode+Size) + %ld = %ld bytes",sizeof(*ssa),allocation_size,total_single_allocation_size)); - #if defined(__amigaos4__) + /* No integer overflow? */ + if(allocation_size < total_single_allocation_size) { - single_allocation = AllocMem(total_single_allocation_size,MEMF_PRIVATE); + #if defined(__amigaos4__) + { + ssa = AllocMem(total_single_allocation_size,MEMF_PRIVATE); + } + #else + { + ssa = AllocMem(total_single_allocation_size,MEMF_ANY); + } + #endif /* __amigaos4__ */ } - #else + /* Integer overflow has occured. */ + else { - single_allocation = AllocMem(total_single_allocation_size,MEMF_ANY); + ssa = NULL; } - #endif /* __amigaos4__ */ - if(single_allocation != NULL) + if(ssa != NULL) { - single_allocation->ssa_Size = total_single_allocation_size; + ssa->ssa_Size = total_single_allocation_size; - allocation = &single_allocation[1]; + allocation = &ssa[1]; D(("single allocation = 0x%08lx",allocation)); - AddTail((struct List *)&__slab_data.sd_SingleAllocations,(struct Node *)single_allocation); + AddTail((struct List *)&__slab_data.sd_SingleAllocations,(struct Node *)ssa); __slab_data.sd_NumSingleAllocations++; __slab_data.sd_TotalSingleAllocationSize += total_single_allocation_size; @@ -116,18 +131,19 @@ __slab_allocate(size_t allocation_size) D(("allocation size is <= %ld; this will be allocated from a slab",__slab_data.sd_StandardSlabSize)); + /* Add room for a pointer back to the slab which + * the chunk belongs to. + */ + entry_size = sizeof(*chunk) + allocation_size; + /* Chunks must be at least as small as a MinNode, because * that's what we use for keeping track of the chunks which * are available for allocation within each slab. */ - entry_size = allocation_size; if(entry_size < sizeof(struct MinNode)) entry_size = sizeof(struct MinNode); - /* Add room for a pointer back to the slab which - * the chunk belongs to. - */ - entry_size += sizeof(*chunk); + D(("final entry size prior to picking slab size = %ld bytes",entry_size)); /* Find a slab which keeps track of chunks that are no * larger than the amount of memory which needs to be @@ -184,9 +200,8 @@ __slab_allocate(size_t allocation_size) { D(("slab is no longer empty")); - /* Mark it as no longer empty. */ + /* Pull it out of the list of slabs available for reuse. */ Remove((struct Node *)&sn->sn_EmptyLink); - sn->sn_EmptyDecay = 0; } sn->sn_UseCount++; @@ -238,7 +253,8 @@ __slab_allocate(size_t allocation_size) Remove((struct Node *)free_node); /* Unlink from list of slabs which keep chunks - * of the same size. + * of the same size. It will be added there + * again, at a different position. */ Remove((struct Node *)sn); @@ -254,21 +270,26 @@ __slab_allocate(size_t allocation_size) */ if(new_sn == NULL) { - D(("no slab is available for reuse; allocating a new slab (%lu bytes)",sizeof(*sn) + __slab_data.sd_StandardSlabSize)); + D(("no slab is available for reuse; allocating a new slab (%lu bytes)",sizeof(*new_sn) + __slab_data.sd_StandardSlabSize)); #if defined(__amigaos4__) { - new_sn = (struct SlabNode *)AllocVec(sizeof(*sn) + __slab_data.sd_StandardSlabSize,MEMF_PRIVATE); + new_sn = (struct SlabNode *)AllocVec(sizeof(*new_sn) + __slab_data.sd_StandardSlabSize,MEMF_PRIVATE); } #else { - new_sn = (struct SlabNode *)AllocVec(sizeof(*sn) + __slab_data.sd_StandardSlabSize,MEMF_ANY); + new_sn = (struct SlabNode *)AllocVec(sizeof(*new_sn) + __slab_data.sd_StandardSlabSize,MEMF_ANY); } #endif /* __amigaos4__ */ if(new_sn == NULL) D(("slab allocation failed")); + /* If this allocation went well, try to free all currently unused + * slabs which are ready for purging. This is done so that we don't + * keep allocating new memory all the time without cutting back on + * unused slabs. + */ purge = TRUE; } @@ -369,7 +390,7 @@ __slab_allocate(size_t allocation_size) if(sn->sn_EmptyDecay == 0) { /* Move it to the front of the list, so that - * will be collected as soon as possible. + * it will be collected as soon as possible. */ if(free_node != (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head) { @@ -405,32 +426,53 @@ __slab_free(void * address,size_t allocation_size) /* Number of bytes allocated exceeds the slab size? * Then the chunk was allocated separately. */ - if(allocation_size + sizeof(*chunk) > __slab_data.sd_StandardSlabSize) + if(sizeof(*chunk) + allocation_size > __slab_data.sd_StandardSlabSize) { - struct SlabSingleAllocation * single_allocation = address; + struct SlabSingleAllocation * ssa = address; ULONG size; D(("allocation size is > %ld; this was stored separately",__slab_data.sd_StandardSlabSize)); + assert( __slab_data.sd_NumSingleAllocations > 0 ); + /* Management information (MinNode linkage, size in bytes) precedes * the address returned by malloc(), etc. */ - single_allocation--; + ssa--; - size = single_allocation->ssa_Size; + /* Verify that the allocation is really on the list we + * will remove it from. + */ + #if DEBUG + { + struct MinNode * mln; + BOOL found_allocation_in_list = FALSE; - assert( sizeof(*single_allocation) + allocation_size == size ); + for(mln = __slab_data.sd_SingleAllocations.mlh_Head ; + mln->mln_Succ != NULL ; + mln = mln->mln_Succ) + { + if(mln == (struct MinNode *)ssa) + { + found_allocation_in_list = TRUE; + break; + } + } - Remove((struct Node *)single_allocation); + assert( found_allocation_in_list ); + } + #endif /* DEBUG */ - FreeMem(single_allocation, size); - - assert( __slab_data.sd_NumSingleAllocations > 0 ); - - __slab_data.sd_NumSingleAllocations--; + size = ssa->ssa_Size; + assert( size > 0 ); + assert( sizeof(*ssa) + allocation_size == size ); assert( size <= __slab_data.sd_TotalSingleAllocationSize ); + Remove((struct Node *)ssa); + FreeMem(ssa, size); + + __slab_data.sd_NumSingleAllocations--; __slab_data.sd_TotalSingleAllocationSize -= size; D(("number of single allocations = %ld", __slab_data.sd_NumSingleAllocations)); @@ -445,19 +487,18 @@ __slab_free(void * address,size_t allocation_size) D(("allocation size is <= %ld; this was allocated from a slab",__slab_data.sd_StandardSlabSize)); + /* Add room for a pointer back to the slab which + * the chunk belongs to. + */ + entry_size = sizeof(*chunk) + allocation_size; + /* Chunks must be at least as small as a MinNode, because * that's what we use for keeping track of the chunks which * are available for allocation within each slab. */ - entry_size = allocation_size; if(entry_size < sizeof(struct MinNode)) entry_size = sizeof(struct MinNode); - /* Add room for a pointer back to the slab which - * the chunk belongs to. - */ - entry_size += sizeof(*chunk); - /* Find a slab which keeps track of chunks that are no * larger than the amount of memory which needs to be * released. We end up picking the smallest chunk @@ -494,13 +535,79 @@ __slab_free(void * address,size_t allocation_size) sn = chunk->sc_Parent; + #if DEBUG + { + struct SlabNode * other_sn; + BOOL slab_found = FALSE; + BOOL chunk_found = FALSE; + + for(other_sn = (struct SlabNode *)slab_list->mlh_Head ; + other_sn->sn_MinNode.mln_Succ != NULL ; + other_sn = (struct SlabNode *)other_sn->sn_MinNode.mln_Succ) + { + if(other_sn == sn) + { + slab_found = TRUE; + break; + } + } + + assert( slab_found ); + + if(slab_found) + { + struct MinNode * free_chunk; + BYTE * first_byte; + BYTE * last_byte; + + first_byte = (BYTE *)&sn[1]; + last_byte = &first_byte[__slab_data.sd_StandardSlabSize - chunk_size]; + + for(free_chunk = (struct MinNode *)first_byte ; + free_chunk <= (struct MinNode *)last_byte; + free_chunk = (struct MinNode *)(((BYTE *)free_chunk) + chunk_size)) + { + if(free_chunk == (struct MinNode *)chunk) + { + chunk_found = TRUE; + break; + } + } + } + + assert( chunk_found ); + } + #endif /* DEBUG */ + SHOWVALUE(sn->sn_ChunkSize); + assert( sn->sn_ChunkSize != 0 ); + assert( sn->sn_ChunkSize == chunk_size ); D(("allocation is part of slab 0x%08lx (slab use count = %ld)",sn,sn->sn_UseCount)); - AddTail((struct List *)&sn->sn_FreeList, (struct Node *)address); + #if DEBUG + { + struct MinNode * mln; + BOOL chunk_already_free = FALSE; + + for(mln = sn->sn_FreeList.mlh_Head ; + mln->mln_Succ != NULL ; + mln = mln->mln_Succ) + { + if(mln == (struct MinNode *)chunk) + { + chunk_already_free = TRUE; + break; + } + } + + assert( NOT chunk_already_free ); + } + #endif /* DEBUG */ + + AddHead((struct List *)&sn->sn_FreeList, (struct Node *)chunk); assert( sn->sn_UseCount > 0 ); @@ -600,7 +707,7 @@ __slab_exit(void) if(__slab_data.sd_InUse) { - struct SlabSingleAllocation * single_allocation; + struct SlabSingleAllocation * ssa; struct SlabNode * sn; struct SlabNode * sn_next; struct MinNode * mn; @@ -637,9 +744,9 @@ __slab_exit(void) { mn_next = mn->mln_Succ; - single_allocation = (struct SlabSingleAllocation *)mn; + ssa = (struct SlabSingleAllocation *)mn; - FreeMem(single_allocation, single_allocation->ssa_Size); + FreeMem(ssa, ssa->ssa_Size); } __slab_data.sd_InUse = FALSE; diff --git a/library/unix.lib_rev.h b/library/unix.lib_rev.h index b933a62..8b03422 100644 --- a/library/unix.lib_rev.h +++ b/library/unix.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 210 -#define DATE "22.11.2016" -#define VERS "unix.lib 1.210" -#define VSTRING "unix.lib 1.210 (22.11.2016)\r\n" -#define VERSTAG "\0$VER: unix.lib 1.210 (22.11.2016)" +#define REVISION 211 +#define DATE "23.11.2016" +#define VERS "unix.lib 1.211" +#define VSTRING "unix.lib 1.211 (23.11.2016)\r\n" +#define VERSTAG "\0$VER: unix.lib 1.211 (23.11.2016)" diff --git a/library/unix.lib_rev.rev b/library/unix.lib_rev.rev index cd7da05..dba40af 100644 --- a/library/unix.lib_rev.rev +++ b/library/unix.lib_rev.rev @@ -1 +1 @@ -210 +211