2000-01-05 09:36:36 +03:00
/*
2002-01-03 08:25:30 +03:00
Samba Unix SMB / Netbios implementation .
2000-01-05 09:36:36 +03:00
Samba temporary memory allocation functions
Copyright ( C ) Andrew Tridgell 2000
2002-01-03 08:25:30 +03:00
Copyright ( C ) 2001 , 2002 by Martin Pool < mbp @ samba . org >
2000-01-05 09:36:36 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2001-12-19 09:00:19 +03:00
/**
@ defgroup talloc Simple memory allocator
@ {
This is a very simple temporary memory allocator . To use it do the following :
2000-01-05 09:36:36 +03:00
1 ) when you first want to allocate a pool of meomry use
talloc_init ( ) and save the resulting context pointer somewhere
2 ) to allocate memory use talloc ( )
3 ) when _all_ of the memory allocated using this context is no longer needed
use talloc_destroy ( )
talloc does not zero the memory . It guarantees memory of a
TALLOC_ALIGN alignment
2001-12-19 09:22:23 +03:00
@ sa talloc . h
2000-01-05 09:36:36 +03:00
*/
2001-12-19 09:22:23 +03:00
/**
* @ todo We could allocate both the talloc_chunk structure , and the
2001-12-19 07:55:58 +03:00
* memory it contains all in one allocation , which might be a bit
* faster and perhaps use less memory overhead .
*
2001-12-20 07:01:44 +03:00
* That smells like a premature optimization , though . - - mbp
* */
/**
* If you want testing for memory corruption , link with dmalloc or use
* Insure + + . It doesn ' t seem useful to duplicate them here .
* */
2001-12-19 07:55:58 +03:00
2000-01-05 09:36:36 +03:00
# include "includes.h"
2001-12-19 10:36:32 +03:00
struct talloc_chunk {
struct talloc_chunk * next ;
size_t size ;
void * ptr ;
} ;
struct talloc_ctx {
struct talloc_chunk * list ;
size_t total_alloc_size ;
/** The name recorded for this pool, if any. Should describe
* the purpose for which it was allocated . The string is
* allocated within the pool . * */
char * name ;
/** Pointer to the next allocate talloc pool, so that we can
* summarize all talloc memory usage . * */
struct talloc_ctx * next_ctx ;
} ;
/**
* Start of linked list of all talloc pools .
* */
TALLOC_CTX * list_head = NULL ;
/**
* Add to the global list
* */
static void talloc_enroll ( TALLOC_CTX * t )
{
t - > next_ctx = list_head ;
list_head = t ;
}
static void talloc_disenroll ( TALLOC_CTX * t )
{
TALLOC_CTX * * ttmp ;
/* Use a double-* so that no special case is required for the
* list head . */
for ( ttmp = & list_head ; * ttmp ; ttmp = & ( ( * ttmp ) - > next_ctx ) )
if ( * ttmp = = t ) {
/* ttmp is the link that points to t, either
* list_head or the next_ctx link in its
* predecessor */
* ttmp = t - > next_ctx ;
t - > next_ctx = NULL ; /* clobber */
return ;
}
abort ( ) ; /* oops, this talloc was already
* clobbered or something else went
* wrong . */
}
2001-12-19 07:50:10 +03:00
/** Create a new talloc context. **/
2000-01-05 09:36:36 +03:00
TALLOC_CTX * talloc_init ( void )
{
TALLOC_CTX * t ;
t = ( TALLOC_CTX * ) malloc ( sizeof ( * t ) ) ;
if ( ! t ) return NULL ;
t - > list = NULL ;
2001-02-27 22:22:02 +03:00
t - > total_alloc_size = 0 ;
2001-12-19 10:36:32 +03:00
t - > name = NULL ;
talloc_enroll ( t ) ;
2000-01-05 09:36:36 +03:00
return t ;
}
2001-12-19 07:50:10 +03:00
/**
* Create a new talloc context , with a name specifying its purpose .
* Please call this in preference to talloc_init ( ) .
* */
2001-12-19 08:02:42 +03:00
TALLOC_CTX * talloc_init_named ( char const * fmt , . . . )
2001-12-19 07:50:10 +03:00
{
TALLOC_CTX * t ;
va_list ap ;
t = talloc_init ( ) ;
2001-12-19 10:36:32 +03:00
if ( fmt ) {
va_start ( ap , fmt ) ;
t - > name = talloc_vasprintf ( t , fmt , ap ) ;
va_end ( ap ) ;
}
2001-12-19 07:50:10 +03:00
return t ;
}
/** Allocate a bit of memory from the specified pool **/
2000-01-05 09:36:36 +03:00
void * talloc ( TALLOC_CTX * t , size_t size )
{
void * p ;
2001-03-24 00:37:30 +03:00
struct talloc_chunk * tc ;
2001-06-22 05:56:16 +04:00
if ( size = = 0 ) return NULL ;
2000-01-05 09:36:36 +03:00
2001-03-24 00:37:30 +03:00
p = malloc ( size ) ;
if ( ! p ) return p ;
2000-08-12 18:14:40 +04:00
2001-03-24 00:37:30 +03:00
tc = malloc ( sizeof ( * tc ) ) ;
if ( ! tc ) {
2001-09-17 06:19:44 +04:00
SAFE_FREE ( p ) ;
2001-03-24 00:37:30 +03:00
return NULL ;
2000-08-10 17:58:15 +04:00
}
2000-08-12 18:14:40 +04:00
2001-03-24 00:37:30 +03:00
tc - > ptr = p ;
tc - > size = size ;
tc - > next = t - > list ;
t - > list = tc ;
t - > total_alloc_size + = size ;
2000-08-12 18:14:40 +04:00
2000-01-05 09:36:36 +03:00
return p ;
}
2001-12-19 09:22:23 +03:00
/** A talloc version of realloc */
2001-03-24 00:37:30 +03:00
void * talloc_realloc ( TALLOC_CTX * t , void * ptr , size_t size )
{
struct talloc_chunk * tc ;
2001-07-03 02:17:58 +04:00
/* size zero is equivalent to free() */
if ( size = = 0 )
return NULL ;
/* realloc(NULL) is equavalent to malloc() */
if ( ptr = = NULL )
return talloc ( t , size ) ;
2001-03-24 00:37:30 +03:00
for ( tc = t - > list ; tc ; tc = tc - > next ) {
if ( tc - > ptr = = ptr ) {
2001-08-08 20:54:16 +04:00
ptr = Realloc ( ptr , size ) ;
2001-03-24 00:37:30 +03:00
if ( ptr ) {
t - > total_alloc_size + = ( size - tc - > size ) ;
tc - > size = size ;
tc - > ptr = ptr ;
}
return ptr ;
}
}
return NULL ;
}
2001-12-19 09:22:23 +03:00
/** Destroy all the memory allocated inside @p t, but not @p t
* itself . */
2000-07-27 04:47:19 +04:00
void talloc_destroy_pool ( TALLOC_CTX * t )
2000-01-05 09:36:36 +03:00
{
struct talloc_chunk * c ;
2000-12-15 04:02:11 +03:00
if ( ! t )
return ;
2000-01-05 09:36:36 +03:00
while ( t - > list ) {
c = t - > list - > next ;
2001-09-17 06:19:44 +04:00
SAFE_FREE ( t - > list - > ptr ) ;
SAFE_FREE ( t - > list ) ;
2000-01-05 09:36:36 +03:00
t - > list = c ;
}
2001-02-27 22:22:02 +03:00
t - > total_alloc_size = 0 ;
2000-07-27 04:47:19 +04:00
}
2001-12-19 09:22:23 +03:00
/** Destroy a whole pool including the context */
2000-07-27 04:47:19 +04:00
void talloc_destroy ( TALLOC_CTX * t )
{
2000-12-15 04:02:11 +03:00
if ( ! t )
return ;
2000-07-27 04:47:19 +04:00
talloc_destroy_pool ( t ) ;
2001-12-19 10:36:32 +03:00
talloc_disenroll ( t ) ;
2001-03-24 00:37:30 +03:00
memset ( t , 0 , sizeof ( * t ) ) ;
2001-09-17 06:19:44 +04:00
SAFE_FREE ( t ) ;
2000-01-05 09:36:36 +03:00
}
2001-02-27 22:22:02 +03:00
2001-12-19 09:22:23 +03:00
/** Return the current total size of the pool. */
2001-02-27 22:22:02 +03:00
size_t talloc_pool_size ( TALLOC_CTX * t )
{
return t - > total_alloc_size ;
}
2001-12-19 10:36:32 +03:00
const char * talloc_pool_name ( TALLOC_CTX const * t )
{
return t - > name ;
}
2001-12-19 09:22:23 +03:00
/** talloc and zero memory. */
2001-02-27 22:22:02 +03:00
void * talloc_zero ( TALLOC_CTX * t , size_t size )
{
void * p = talloc ( t , size ) ;
if ( p )
memset ( p , ' \0 ' , size ) ;
return p ;
}
2001-02-28 03:51:02 +03:00
2001-12-19 09:22:23 +03:00
/** memdup with a talloc. */
2001-12-04 09:14:42 +03:00
void * talloc_memdup ( TALLOC_CTX * t , const void * p , size_t size )
2001-02-28 03:51:02 +03:00
{
void * newp = talloc ( t , size ) ;
if ( ! newp )
return 0 ;
memcpy ( newp , p , size ) ;
return newp ;
}
2001-05-11 11:03:13 +04:00
2001-12-19 09:22:23 +03:00
/** strdup with a talloc */
2001-12-04 09:14:42 +03:00
char * talloc_strdup ( TALLOC_CTX * t , const char * p )
2001-05-11 11:03:13 +04:00
{
return talloc_memdup ( t , p , strlen ( p ) + 1 ) ;
}
2001-10-13 16:47:59 +04:00
2001-12-19 07:50:10 +03:00
/**
* Perform string formatting , and return a pointer to newly allocated
* memory holding the result , inside a memory pool .
* */
2001-12-19 08:02:42 +03:00
char * talloc_asprintf ( TALLOC_CTX * t , const char * fmt , . . . )
2001-10-13 16:47:59 +04:00
{
va_list ap ;
2001-10-14 13:32:14 +04:00
char * ret ;
2001-10-13 16:47:59 +04:00
va_start ( ap , fmt ) ;
2001-12-19 07:50:10 +03:00
ret = talloc_vasprintf ( t , fmt , ap ) ;
2001-10-13 16:47:59 +04:00
va_end ( ap ) ;
2001-12-19 07:50:10 +03:00
return ret ;
}
2001-12-19 08:02:42 +03:00
char * talloc_vasprintf ( TALLOC_CTX * t , const char * fmt , va_list ap )
2001-12-19 07:50:10 +03:00
{
int len ;
char * ret ;
2001-10-14 13:32:14 +04:00
2001-12-19 07:50:10 +03:00
len = vsnprintf ( NULL , 0 , fmt , ap ) ;
2001-10-14 16:40:26 +04:00
ret = talloc ( t , len + 1 ) ;
2001-10-14 13:32:14 +04:00
if ( ! ret ) return NULL ;
2001-10-13 16:47:59 +04:00
2001-12-05 07:43:53 +03:00
vsnprintf ( ret , len + 1 , fmt , ap ) ;
2001-10-13 16:47:59 +04:00
2001-10-14 13:32:14 +04:00
return ret ;
2001-10-13 16:47:59 +04:00
}
2001-12-19 09:00:19 +03:00
2002-01-03 08:25:30 +03:00
/**
* Realloc @ p s to append the formatted result of @ p fmt and return @ p
* s , which may have moved . Good for gradually accumulating output
* into a string buffer .
* */
char * talloc_asprintf_append ( TALLOC_CTX * t , char * s ,
const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
s = talloc_vasprintf_append ( t , s , fmt , ap ) ;
va_end ( ap ) ;
return s ;
}
/**
* Realloc @ p s to append the formatted result of @ p fmt and @ p ap ,
* and return @ p s , which may have moved . Good for gradually
* accumulating output into a string buffer .
* */
char * talloc_vasprintf_append ( TALLOC_CTX * t , char * s ,
const char * fmt , va_list ap )
{
int len , s_len ;
s_len = strlen ( s ) ;
len = vsnprintf ( NULL , 0 , fmt , ap ) ;
s = talloc_realloc ( t , s , s_len + len + 1 ) ;
if ( ! s ) return NULL ;
vsnprintf ( s + s_len , len + 1 , fmt , ap ) ;
return s ;
}
/**
* Return a human - readable description of all talloc memory usage .
* The result is allocated from @ p t .
* */
char * talloc_describe_all ( TALLOC_CTX * t )
{
int n_pools = 0 ;
size_t total = 0 ;
TALLOC_CTX * titer ;
char * s ;
s = talloc_asprintf ( t , " global talloc allocations in pid%u: \n " ,
( unsigned ) getpid ( ) ) ;
s = talloc_asprintf_append ( t , s , " name \n ---- \n " ) ;
for ( titer = list_head ; titer ; titer = titer - > next_ctx ) {
n_pools + + ;
s = talloc_asprintf_append ( t , s , " \" %s \" \n " , titer - > name ) ;
}
s = talloc_asprintf_append ( t , s , " ----- \n Total %d pools \n " , n_pools ) ;
return s ;
}
/**
* Return an estimated memory usage for the specified pool . This does
* not include memory used by the underlying malloc implementation .
* */
2001-12-19 09:00:19 +03:00
/** @} */