2006-02-07 00:25:02 +10:00
/** \file halloc.c
2006-02-07 04:11:01 +10:00
A hierarchical memory allocation system . Works just like talloc
used in Samba , except that an arbitrary block allocated with
malloc ( ) can be registered to be freed by halloc_free .
2006-02-07 00:25:02 +10:00
*/
# include "config.h"
2006-02-28 23:17:16 +10:00
2006-02-07 00:25:02 +10:00
# include <stdlib.h>
# include <unistd.h>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2006-02-07 00:25:02 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2006-02-07 00:25:02 +10:00
# include "common.h"
# include "halloc.h"
2006-06-20 10:50:10 +10:00
/**
Extra size to allocate whenever doing a halloc , in order to fill uyp smaller halloc calls
*/
2006-02-12 23:18:46 +10:00
# define HALLOC_BLOCK_SIZE 128
2006-06-20 10:50:10 +10:00
/**
Maximum size of trailing halloc space to refuse to discard
*/
2006-02-11 10:13:17 +10:00
# define HALLOC_SCRAP_SIZE 16
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-06-20 10:50:10 +10:00
/**
Debug statistic parameter
*/
2006-02-11 10:13:17 +10:00
static int child_count = 0 ;
2006-06-20 10:50:10 +10:00
/**
Debug statistic parameter
*/
2006-02-11 10:13:17 +10:00
static int child_size = 0 ;
2006-06-20 10:50:10 +10:00
/**
Debug statistic parameter
*/
2006-02-11 10:13:17 +10:00
static int alloc_count = 0 ;
2006-06-20 10:50:10 +10:00
/**
Debug statistic parameter
*/
2006-02-11 10:13:17 +10:00
static int alloc_spill = 0 ;
2006-06-20 10:50:10 +10:00
/**
Debug statistic parameter
*/
2006-02-11 10:13:17 +10:00
static pid_t pid = 0 ;
2006-06-20 10:50:10 +10:00
/**
Debug statistic parameter
*/
2006-02-11 10:13:17 +10:00
static int parent_count = 0 ;
2006-02-12 23:18:46 +10:00
# endif
2006-02-11 10:13:17 +10:00
2006-06-20 10:50:10 +10:00
/**
The main datastructure for a main halloc context
*/
2006-02-07 00:25:02 +10:00
typedef struct halloc
{
2006-06-20 10:50:10 +10:00
/**
List of all addresses and functions to call on them
*/
2006-02-07 00:25:02 +10:00
array_list_t children ;
2006-06-20 10:50:10 +10:00
/**
Memory scratch area used to fullfil smaller memory allocations
*/
2006-02-11 10:13:17 +10:00
void * scratch ;
2006-06-20 10:50:10 +10:00
/**
Amount of free space in the scratch area
*/
2006-02-11 10:13:17 +10:00
size_t scratch_free ;
2006-06-20 10:50:10 +10:00
# if __STDC_VERSION__ < 199901L
/**
The actual data . MAde to be of type long long to make sure memory alignment is in order .
*/
long long data [ 1 ] ; // Waste one byte on non-C99 compilers... :-(
# else
long long data [ ] ;
# endif
2006-02-07 00:25:02 +10:00
}
halloc_t ;
2006-06-20 10:50:10 +10:00
/**
Get the offset of the halloc structure before a data block
*/
2006-02-07 00:25:02 +10:00
static halloc_t * halloc_from_data ( void * data )
{
2006-03-29 10:14:50 +10:00
return ( halloc_t * ) ( ( ( char * ) data ) - sizeof ( halloc_t ) ) ;
2006-02-07 00:25:02 +10:00
}
2006-06-20 10:50:10 +10:00
/**
A function that does nothing
*/
2006-02-11 10:13:17 +10:00
static void late_free ( void * data )
{
}
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-06-20 10:50:10 +10:00
/**
Debug function , called at exit when in debug mode . Prints usage
statistics , like number of allocations and number of internal calls
to malloc .
*/
2006-02-11 10:13:17 +10:00
static void woot ( )
{
if ( getpid ( ) = = pid )
{
debug ( 1 , L " %d parents, %d children with average child size of %.2f bytes caused %d allocs, average spill of %.2f bytes " ,
parent_count , child_count , ( double ) child_size / child_count ,
parent_count + alloc_count , ( double ) alloc_spill / ( parent_count + alloc_count ) ) ;
}
}
2006-02-12 23:18:46 +10:00
# endif
2006-02-07 00:25:02 +10:00
void * halloc ( void * context , size_t size )
2006-02-10 01:50:20 +10:00
{
2006-02-07 04:11:01 +10:00
halloc_t * me , * parent ;
2006-02-07 00:25:02 +10:00
if ( context )
2006-02-11 10:13:17 +10:00
{
void * res ;
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-02-11 10:13:17 +10:00
if ( ! child_count )
{
pid = getpid ( ) ;
atexit ( woot ) ;
}
child_count + + ;
child_size + = size ;
2006-02-12 23:18:46 +10:00
# endif
2006-02-07 04:11:01 +10:00
parent = halloc_from_data ( context ) ;
2006-02-11 10:13:17 +10:00
if ( size < = parent - > scratch_free )
{
res = parent - > scratch ;
parent - > scratch_free - = size ;
2006-03-29 10:14:50 +10:00
parent - > scratch = ( ( char * ) parent - > scratch ) + size ;
2006-02-11 10:13:17 +10:00
}
else
{
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-02-11 10:13:17 +10:00
alloc_count + + ;
2006-02-12 23:18:46 +10:00
# endif
2006-02-11 10:13:17 +10:00
if ( parent - > scratch_free < HALLOC_SCRAP_SIZE )
{
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-02-11 10:13:17 +10:00
alloc_spill + = parent - > scratch_free ;
2006-02-12 23:18:46 +10:00
# endif
2006-02-11 10:13:17 +10:00
res = calloc ( 1 , size + HALLOC_BLOCK_SIZE ) ;
2006-03-29 10:14:50 +10:00
parent - > scratch = ( char * ) res + size ;
2006-02-11 10:13:17 +10:00
parent - > scratch_free = HALLOC_BLOCK_SIZE ;
}
else
{
res = calloc ( 1 , size ) ;
}
al_push ( & parent - > children , & late_free ) ;
al_push ( & parent - > children , res ) ;
}
return res ;
2006-02-10 01:50:20 +10:00
2006-02-11 10:13:17 +10:00
}
else
{
me = ( halloc_t * ) calloc ( 1 , sizeof ( halloc_t ) + size + HALLOC_BLOCK_SIZE ) ;
if ( ! me )
return 0 ;
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-02-11 10:13:17 +10:00
parent_count + + ;
2006-02-12 23:18:46 +10:00
# endif
2006-03-29 10:14:50 +10:00
me - > scratch = ( ( char * ) me ) + sizeof ( halloc_t ) + size ;
2006-02-11 10:13:17 +10:00
me - > scratch_free = HALLOC_BLOCK_SIZE ;
al_init ( & me - > children ) ;
return & me - > data ;
}
2006-02-07 00:25:02 +10:00
}
2006-02-10 01:50:20 +10:00
void halloc_register_function ( void * context , void ( * func ) ( void * ) , void * data )
2006-02-07 00:25:02 +10:00
{
halloc_t * me ;
if ( ! context )
2006-02-10 01:50:20 +10:00
return ;
2006-02-07 00:25:02 +10:00
me = halloc_from_data ( context ) ;
2006-02-10 01:50:20 +10:00
al_push ( & me - > children , func ) ;
2006-02-07 04:11:01 +10:00
al_push ( & me - > children , data ) ;
2006-02-07 00:25:02 +10:00
}
2006-02-07 04:11:01 +10:00
void halloc_free ( void * context )
2006-02-07 00:25:02 +10:00
{
2006-02-07 04:11:01 +10:00
halloc_t * me ;
2006-02-10 01:50:20 +10:00
int i ;
2006-02-07 04:11:01 +10:00
if ( ! context )
return ;
2006-02-11 10:13:17 +10:00
2006-02-10 01:50:20 +10:00
2006-02-07 04:11:01 +10:00
me = halloc_from_data ( context ) ;
2006-02-11 10:13:17 +10:00
2006-02-12 23:18:46 +10:00
# ifdef HALLOC_DEBUG
2006-02-11 10:13:17 +10:00
alloc_spill + = me - > scratch_free ;
2006-02-12 23:18:46 +10:00
# endif
2006-02-11 10:13:17 +10:00
for ( i = 0 ; i < al_get_count ( & me - > children ) ; i + = 2 )
{
void ( * func ) ( void * ) = ( void ( * ) ( void * ) ) al_get ( & me - > children , i ) ;
void * data = ( void * ) al_get ( & me - > children , i + 1 ) ;
if ( func ! = & late_free )
func ( data ) ;
}
2006-02-10 01:50:20 +10:00
for ( i = 0 ; i < al_get_count ( & me - > children ) ; i + = 2 )
{
void ( * func ) ( void * ) = ( void ( * ) ( void * ) ) al_get ( & me - > children , i ) ;
void * data = ( void * ) al_get ( & me - > children , i + 1 ) ;
2006-02-11 10:13:17 +10:00
if ( func = = & late_free )
free ( data ) ;
2006-02-10 01:50:20 +10:00
}
2006-02-07 04:11:01 +10:00
al_destroy ( & me - > children ) ;
free ( me ) ;
2006-02-07 00:25:02 +10:00
}