/* ----------------------------------------------------------------------------- * * Copyright (c) 2007-2022 Alexis Naveros. * Portions developed under contract to the SURVICE Engineering Company. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * ----------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include "mmslab.h" //// #ifndef ADDRESS #define ADDRESS(p,o) ((void *)(((char *)p)+(o))) #endif typedef struct { void **prev; void *next; } mmListNode; static inline void mmListAdd( void **list, void *item, intptr_t offset ) { mmListNode *node, *next; node = ADDRESS( item, offset ); node->prev = list; node->next = *list; if( *list ) { next = ADDRESS( *list, offset ); next->prev = &(node->next); } *list = item; return; } static inline void mmListRemove( void *item, intptr_t offset ) { mmListNode *node, *next; node = ADDRESS( item, offset ); *(node->prev) = (void *)node->next; if( node->next ) { next = ADDRESS( node->next, offset ); next->prev = node->prev; } return; } //// typedef struct { void *nextblock; } mmSlabBlock; void mmSlabInit( mmSlab *slab, size_t chunksize, size_t chunkperblock, size_t alignment ) { memset( slab, 0, sizeof(mmSlab) ); slab->alignment = 0; slab->chunksize = chunksize; if( slab->chunksize < sizeof(mmListNode) ) slab->chunksize = sizeof(mmListNode); if( alignment >= 0x10 ) { slab->alignment = alignment - 1; slab->chunksize = ( chunksize + slab->alignment ) & ~slab->alignment; } slab->blockcount = 0; slab->chunkperblock = chunkperblock; slab->allocsize = sizeof(mmSlabBlock) + slab->chunksize * slab->chunkperblock; return; } void *mmSlabAlloc( mmSlab *slab ) { size_t chunkindex, blockwidth, chunkcount; size_t chunkallocsize; mmSlabBlock *block; void *chunkdata; void *chunk; if( !( slab->freelist ) ) { /* How aggressive should this be? */ blockwidth = 1 + ( slab->blockcount >> 2 ); chunkallocsize = slab->chunksize * slab->chunkperblock; block = malloc( sizeof(mmSlabBlock)+ slab->alignment + ( blockwidth * chunkallocsize ) ); block->nextblock = slab->blocklist; slab->blocklist = block; chunkdata = (void *)( ( (uintptr_t)block + sizeof(mmSlabBlock) + slab->alignment ) & ~slab->alignment ); chunkcount = blockwidth * slab->chunkperblock; chunk = chunkdata; for( chunkindex = 0 ; chunkindex < chunkcount ; chunkindex++, chunk = ADDRESS( chunk, slab->chunksize ) ) mmListAdd( &slab->freelist, chunk, 0 ); slab->blockcount += blockwidth; } chunk = slab->freelist; mmListRemove( chunk, 0 ); return chunk; } void mmSlabRelease( mmSlab *slab, void *v ) { void *chunk; chunk = v; mmListAdd( &slab->freelist, chunk, 0 ); return; } void mmSlabFreeAll( mmSlab *slab ) { mmSlabBlock *block, *blocknext; for( block = slab->blocklist ; block ; block = blocknext ) { blocknext = block->nextblock; free( block ); } slab->blocklist = 0; slab->freelist = 0; return; }