2007-08-30 23:48:31 +04:00
/*
Unix SMB / CIFS implementation .
Implement a stack of talloc contexts
Copyright ( C ) Volker Lendecke 2007
2009-04-14 23:23:22 +04:00
Copyright ( C ) Jeremy Allison 2009 - made thread safe .
2007-08-30 23:48:31 +04: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 .
*/
/*
* Implement a stack of talloc frames .
*
* When a new talloc stackframe is allocated with talloc_stackframe ( ) , then
* the TALLOC_CTX returned with talloc_tos ( ) is reset to that new
* frame . Whenever that stack frame is TALLOC_FREE ( ) ' ed , then the reverse
* happens : The previous talloc_tos ( ) is restored .
*
* This API is designed to be robust in the sense that if someone forgets to
* TALLOC_FREE ( ) a stackframe , then the next outer one correctly cleans up and
* resets the talloc_tos ( ) .
*
* This robustness feature means that we can ' t rely on a linked list with
* talloc destructors because in a hierarchy of talloc destructors the parent
* destructor is called before its children destructors . The child destructor
* called after the parent would set the talloc_tos ( ) to the wrong value .
*/
# include "includes.h"
2009-04-14 23:23:22 +04:00
struct talloc_stackframe {
int talloc_stacksize ;
int talloc_stack_arraysize ;
TALLOC_CTX * * talloc_stack ;
} ;
/*
* In the single threaded case this is a pointer
* to the global talloc_stackframe . In the MT - case
* this is the pointer to the thread - specific key
* used to look up the per - thread talloc_stackframe
* pointer .
*/
static void * global_ts ;
static struct talloc_stackframe * talloc_stackframe_init ( void )
{
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef malloc
# undef malloc
# endif
# endif
struct talloc_stackframe * ts =
( struct talloc_stackframe * ) malloc ( sizeof ( struct talloc_stackframe ) ) ;
# if defined(PARANOID_MALLOC_CHECKER)
# define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
# endif
if ( ! ts ) {
smb_panic ( " talloc_stackframe_init malloc failed " ) ;
}
ZERO_STRUCTP ( ts ) ;
2009-04-15 02:19:39 +04:00
if ( SMB_THREAD_CREATE_TLS_ONCE ( " talloc_stackframe " , global_ts ) ) {
2009-04-14 23:23:22 +04:00
smb_panic ( " talloc_stackframe_init create_tls failed " ) ;
}
if ( SMB_THREAD_SET_TLS ( global_ts , ts ) ) {
smb_panic ( " talloc_stackframe_init set_tls failed " ) ;
}
return ts ;
}
2007-08-30 23:48:31 +04:00
2008-01-06 19:25:20 +03:00
static int talloc_pop ( TALLOC_CTX * frame )
2007-08-30 23:48:31 +04:00
{
2009-04-14 23:23:22 +04:00
struct talloc_stackframe * ts =
( struct talloc_stackframe * ) SMB_THREAD_GET_TLS ( global_ts ) ;
2007-08-30 23:48:31 +04:00
int i ;
2009-04-14 23:23:22 +04:00
for ( i = ts - > talloc_stacksize - 1 ; i > 0 ; i - - ) {
if ( frame = = ts - > talloc_stack [ i ] ) {
2008-01-06 19:25:20 +03:00
break ;
}
2009-04-14 23:23:22 +04:00
talloc_free ( ts - > talloc_stack [ i ] ) ;
2007-08-30 23:48:31 +04:00
}
2009-04-14 23:23:22 +04:00
ts - > talloc_stacksize = i ;
2007-08-30 23:48:31 +04:00
return 0 ;
}
/*
* Create a new talloc stack frame .
*
* When free ' d , it frees all stack frames that were created after this one and
* not explicitly freed .
*/
2008-01-10 04:07:58 +03:00
static TALLOC_CTX * talloc_stackframe_internal ( size_t poolsize )
2007-08-30 23:48:31 +04:00
{
2008-01-10 11:53:51 +03:00
TALLOC_CTX * * tmp , * top , * parent ;
2009-04-14 23:23:22 +04:00
struct talloc_stackframe * ts =
( struct talloc_stackframe * ) SMB_THREAD_GET_TLS ( global_ts ) ;
2007-08-30 23:48:31 +04:00
2009-04-14 23:23:22 +04:00
if ( ts = = NULL ) {
ts = talloc_stackframe_init ( ) ;
}
if ( ts - > talloc_stack_arraysize < ts - > talloc_stacksize + 1 ) {
tmp = talloc_realloc ( NULL , ts - > talloc_stack , TALLOC_CTX * ,
ts - > talloc_stacksize + 1 ) ;
2008-01-09 00:12:35 +03:00
if ( tmp = = NULL ) {
goto fail ;
}
2009-04-14 23:23:22 +04:00
ts - > talloc_stack = tmp ;
ts - > talloc_stack_arraysize = ts - > talloc_stacksize + 1 ;
2008-01-09 00:12:35 +03:00
}
2007-08-30 23:48:31 +04:00
2009-04-14 23:23:22 +04:00
if ( ts - > talloc_stacksize = = 0 ) {
parent = ts - > talloc_stack ;
} else {
parent = ts - > talloc_stack [ ts - > talloc_stacksize - 1 ] ;
2008-01-10 11:53:51 +03:00
}
2008-01-10 04:07:58 +03:00
if ( poolsize ) {
2008-01-10 11:53:51 +03:00
top = talloc_pool ( parent , poolsize ) ;
2008-01-10 04:07:58 +03:00
} else {
2008-01-10 11:53:51 +03:00
top = talloc_new ( parent ) ;
2008-01-10 04:07:58 +03:00
}
2007-08-30 23:48:31 +04:00
2008-01-09 00:12:35 +03:00
if ( top = = NULL ) {
2007-08-30 23:48:31 +04:00
goto fail ;
}
2008-01-06 19:25:20 +03:00
talloc_set_destructor ( top , talloc_pop ) ;
2007-08-30 23:48:31 +04:00
2009-04-14 23:23:22 +04:00
ts - > talloc_stack [ ts - > talloc_stacksize + + ] = top ;
2007-08-30 23:48:31 +04:00
return top ;
fail :
smb_panic ( " talloc_stackframe failed " ) ;
return NULL ;
}
2008-01-10 04:07:58 +03:00
TALLOC_CTX * talloc_stackframe ( void )
{
return talloc_stackframe_internal ( 0 ) ;
}
TALLOC_CTX * talloc_stackframe_pool ( size_t poolsize )
{
return talloc_stackframe_internal ( poolsize ) ;
}
2007-08-30 23:48:31 +04:00
/*
* Get us the current top of the talloc stack .
*/
TALLOC_CTX * talloc_tos ( void )
{
2009-04-14 23:23:22 +04:00
struct talloc_stackframe * ts =
( struct talloc_stackframe * ) SMB_THREAD_GET_TLS ( global_ts ) ;
if ( ts = = NULL ) {
2007-08-30 23:48:31 +04:00
talloc_stackframe ( ) ;
2009-04-14 23:23:22 +04:00
ts = ( struct talloc_stackframe * ) SMB_THREAD_GET_TLS ( global_ts ) ;
2007-09-02 21:48:01 +04:00
DEBUG ( 0 , ( " no talloc stackframe around, leaking memory \n " ) ) ;
2007-08-30 23:48:31 +04:00
}
2009-04-14 23:23:22 +04:00
return ts - > talloc_stack [ ts - > talloc_stacksize - 1 ] ;
2007-08-30 23:48:31 +04:00
}