ctlnew.c

Go to the documentation of this file.
00001 
00006 #include "ctl/ctldef.h"
00007 #include "ctl/ll.h"
00008 #include "ctl/debug.h"
00009 
00010 #ifndef CTL_UNIT
00011 
00013 static void ctl_defaultnewhandler( const char* sz, size_t needed )
00014 {
00015     debug_log( LOG_ERROR, "%s\nAllocation failure, needed %d bytes\n", sz, needed );
00016     exit(EXIT_FAILURE);
00017 }
00018 
00020 static ctl_newhandler curr_newhandler = ctl_defaultnewhandler;
00021 
00023 ctl_newhandler ctl_set_new_handler( ctl_newhandler handler )
00024 {
00025     ctl_newhandler ret = curr_newhandler;
00026     curr_newhandler = handler ? handler : ctl_defaultnewhandler;
00027     assertcodeptr(curr_newhandler);
00028     return ret;
00029 }
00030 
00034 typedef void (*destruct_t)(void*);
00035 typedef struct AllocList
00036 {
00037 #ifndef NDEBUG
00038     uint32      check;      
00039     dll_decllink(struct AllocList,allocated);   
00040     const char* szFileLine; 
00041 #define HEAD_CHECK      0xBEA75F0D
00042 #define TAIL_CHECK      0x0D5FA7BE
00043 #define MEM_ABSURDREFS  100000001
00044 #endif
00045     int32       refcount;   
00046     size_t      size;       
00047     destruct_t  destruct;   
00048 ppDebug(uint32  check2;     )
00049 } AllocList;
00050 dll_autolist(AllocList,allocated, memoryList);
00051 
00052 #define ALLOC_MOD               4
00053 #define ALLOC_OFFSET(ptr)       ((ptr)?((AllocList*)(ptr)+1):(AllocList*)(ptr))
00054 #define DETAIL_OFFSET(ptr)      ((ptr)?((AllocList*)(ptr)-1):(AllocList*)(ptr))
00055 #define ALLOC_EXCESS(size)      ( sizeof(AllocList) + (size) + sizeof(uint32) )
00056 #define ALLOC_TAILPTR(ptr)      ((uint32*)((uint8*)ptr+(DETAIL_OFFSET(ptr)->size)))
00057 #define DETAIL_TAILPTR(data)    ((uint32*)((uint8*)(data+1)+((data)->size)))
00058 
00062 static void justmemory( void* pmem )
00063 {
00064 #if !defined(NDEBUG) || defined(CTL_FILL_FREE)
00065 #ifndef CTL_FILL_FREE 
00066 #define CTL_FILL_FREE 0xFD
00067 #endif
00068     AllocList* data = DETAIL_OFFSET(pmem);
00069     memset( data, CTL_FILL_FREE+0, ALLOC_EXCESS(data->size) );
00070 #endif
00071 }
00072 
00073 bool _ctlmalloc( void** ptr, size_t size    ppDebugParam(const char* szFileLine) )
00074 {
00075     size_t needsize = ALLOC_EXCESS(size);
00076     void* newptr = malloc( needsize );
00077     if( NULL == newptr )
00078     {
00079         assertcodeptr(curr_newhandler);
00080         curr_newhandler( ppDebRel(szFileLine,"_ctlmalloc"), size );
00081         newptr = malloc( needsize );
00082         if( NULL == newptr )
00083             curr_newhandler( ppDebRel(szFileLine,"_ctlmalloc"), size );
00084     }
00085     if( NULL == newptr )
00086     {
00087         *ptr = NULL;
00088         return false;
00089     }
00090     else
00091     {
00092         AllocList* data = (AllocList*)(newptr);
00093         data->size = size;
00094         data->refcount = 1;
00095         data->destruct = justmemory;
00096 #ifndef NDEBUG
00097         /* Add to memory dumping list */
00098         dll_push_back(AllocList,allocated, memoryList, data);
00099         data->szFileLine = szFileLine;
00100         /* Update sacrificial data points */
00101         data->check = data->check2 = HEAD_CHECK;
00102         /* Check for memory stomp from this allocated data */
00103         *DETAIL_TAILPTR(data) = TAIL_CHECK;
00104 #endif
00105         *ptr = ALLOC_OFFSET(newptr);
00106     }
00107     return true;
00108 }
00109 
00110 bool _ctlcalloc( void** ptr, size_t size    ppDebugParam(const char* szFileLine) )
00111 {
00112     *ptr = NULL;
00113     if( _ctlmalloc( ptr, size   ppDebugParam(szFileLine) ) )
00114     {
00115         memset( ptr, 0, size );
00116         return true;
00117     }
00118     return false;
00119 }
00120 
00121 bool _ctlrealloc( void** ptr, size_t size       ppDebugParam(const char* szFileLine) )
00122 {
00123     void* newptr;
00124     if( NULL == *ptr )
00125     {
00126         _ctlmalloc( ptr, size   ppDebugParam(szFileLine) );
00127         return NULL != *ptr;
00128     }
00129     else
00130     {
00131         size_t needsize = ALLOC_EXCESS(size);
00132         AllocList* data = DETAIL_OFFSET(*ptr);
00133         assert( _ctlvalidate( *ptr, szFileLine ) );
00134         /* Unlink from memory dumping list */
00135         ppDebug(dll_erase( AllocList,allocated, memoryList, data);)
00136         /* Keep trying until success */
00137         newptr = realloc( data, needsize );
00138         if( NULL == newptr )
00139         {
00140             assertcodeptr(curr_newhandler);
00141             curr_newhandler( ppDebRel(szFileLine,"_ctlrealloc"), size );
00142             newptr = realloc( data, needsize );
00143             if( NULL == newptr )
00144             {
00145                 curr_newhandler( ppDebRel(szFileLine,"_ctlrealloc"), size );
00146                 /* Failed, but original pointer is 'still good', just too small */
00147                 ppDebug(dll_push_back(AllocList,allocated, memoryList, data);)
00148                 return false;
00149             }
00150         }
00151     }
00152     {
00153         AllocList* data = (AllocList*)newptr;
00154         *ptr = ALLOC_OFFSET(newptr);
00155         data->size = size;
00156         /*  These were already set and copied
00157             data->refcount = 1;
00158             data->destruct = justmemory;
00159          */
00160 #ifndef NDEBUG
00161         /* Link back to memory dumping list */
00162         dll_push_back(AllocList,allocated, memoryList, data);
00163         /* Check for memory stomp from this allocated data */
00164         *DETAIL_TAILPTR(data) = TAIL_CHECK;
00165         /*
00166             These were already set and copied
00167             Keep original allocation file stamp since this hasn't failed
00168             data->szFileLine = szFileLine;
00169             data->check = data->check2 = HEAD_CHECK;
00170         */
00171 #endif
00172     }
00173     return true;
00174 }
00175 
00176 
00177 void _ctlfree( void** ptr   ppDebugParam(const char* szFileLine) )
00178 {
00179     if( *ptr )
00180     {
00181         AllocList* data = DETAIL_OFFSET(*ptr);
00182         assert( _ctlvalidate( *ptr, szFileLine ) );
00183         assert( data->refcount <= 1 );
00184 
00185         /* Remove from memory dumping list */
00186 #ifndef NDEBUG
00187         dll_erase( AllocList,allocated, memoryList, data);
00188 #endif
00189         assertcodeptr(data->destruct);
00190         data->destruct(*ptr);
00191         free(DETAIL_OFFSET(*ptr));
00192         *ptr = NULL;
00193     }
00194 }
00195 
00196 size_t _ctlsize( void* ptr  ppDebugParam(const char* szFileLine) )
00197 {
00198     if( NULL != ptr )
00199     {
00200         assert( _ctlvalidate( ptr, szFileLine ) );
00201         return DETAIL_OFFSET(ptr)->size;
00202     }
00203     return 0;
00204 }
00205 
00206 bool _ctlstrdup( char** ptr, const char* sz     ppDebugParam(const char* szFileLine) )
00207 {
00208     if( _ctlmalloc( (void**)ptr, strlen(sz) + sizeof(char) ppDebugParam(szFileLine) ) )
00209     {
00210         strcpy( *ptr, sz );
00211         return true;
00212     }
00213     return false;
00214 }
00215 
00216 bool _ctlwcsdup( wchar_t** ptr, const wchar_t*sz    ppDebugParam(const char* szFileLine) )
00217 {
00218     if( _ctlmalloc( (void**)ptr, wcslen(sz) + sizeof(wchar_t) ppDebugParam(szFileLine) ) )
00219     {
00220         wcscpy( *ptr, sz );
00221         return true;
00222     }
00223     return false;
00224 }
00225 
00226 /*
00227  * Allocate new reference-counted object with destructor
00228  */
00229 bool _ctlnew( void** ptr, size_t size, void (*destruct)(void*)  ppDebugParam(const char* szFileLine) )
00230 {
00231     assertptr(ptr,sizeof(void*));
00232     if( _ctlmalloc( ptr, size ppDebugParam(szFileLine) ) )
00233     {
00234         AllocList* data = DETAIL_OFFSET(*ptr);
00235         data->destruct = destruct;
00236         return true;
00237     }
00238     return false;
00239 }
00240 /*
00241  * Destroy reference-counted object
00242  */
00243 int _ctldelete( void** ptr  ppDebugParam(const char* szFileLine) )
00244 {
00245     if( NULL != *ptr )
00246     {
00247         AllocList* data = DETAIL_OFFSET(*ptr);
00248         assert( _ctlvalidate( *ptr, szFileLine ) );
00249         if( 0 == --data->refcount )
00250         {
00251             _ctlfree( ptr   ppDebugParam(szFileLine) );
00252         }
00253         else
00254         {
00255             *ptr = NULL;
00256         }
00257         return data->refcount;
00258     }
00259     return 0;
00260 }
00261 
00262 /*
00263  * Add a reference to a reference-counted object
00264  */
00265 int _ctlref( void* ptr      ppDebugParam(const char* szFileLine))
00266 {
00267     if( NULL != ptr )
00268     {
00269         AllocList* data = DETAIL_OFFSET(ptr);
00270         assert( _ctlvalidate( ptr, szFileLine ) );
00271         return ++data->refcount;
00272     }
00273     return 0;
00274 }
00275 
00276 
00277 /*
00278  * Report reference count.  
00279  * If ptr is valid but no reference has been added yet, returns 1
00280  */
00281 int _ctlrefcount( void* ptr ppDebugParam(const char* szFileLine) )
00282 {
00283     if( NULL != ptr )
00284     {
00285         AllocList* data = DETAIL_OFFSET(ptr);
00286         assert( _ctlvalidate( ptr, szFileLine ) );
00287         return data->refcount;
00288     }
00289     return 0;
00290 }
00291 
00292 #ifndef NDEBUG
00293 bool _ctlvalidate( void* ptr, const char* szFileLine )
00294 {
00295     if( (size_t)ptr > 0x10000 && (0 == ((size_t)(ptr) & 3)) )
00296     {
00297         AllocList* data = DETAIL_OFFSET(ptr);
00298         uint32* tailptr;
00299         if( data->check != HEAD_CHECK || data->check2 != HEAD_CHECK )
00300         {
00301             /* Don't look at data within the possibly corrupt header */
00302             trace(("Memory pointer %p failed header validation\n", ptr ));
00303             trace(("Doing %.128s\n", szFileLine));
00304             return false;
00305         }
00306         /* Reasonable certainty that the header is sort-of valid-looking */
00307         tailptr = DETAIL_TAILPTR(data);
00308         if( data->refcount >= 0 && data->refcount < MEM_ABSURDREFS && *tailptr == TAIL_CHECK )
00309             return true;
00310         assertcodeptr(data->destruct);
00311         trace(("Memory pointer %p failed validation\n", ptr));
00312         trace(("Doing %.128s\n", szFileLine));
00313         trace(("Came from %.128s\n", data->szFileLine));
00314         trace(("Tail: %08x == %08x\n", *tailptr,TAIL_CHECK));
00315         return false;
00316     }
00317     trace(("Bad pointer %p\n", ptr));
00318     return false;
00319 }
00325 size_t ctl_memory_dump( uint32 logmask )
00326 {
00327     size_t count = 0;
00328     dll_foreach( AllocList,allocated, memoryList, curr )
00329     {
00330         count++;
00331         if( curr->check == HEAD_CHECK  && curr->check2 == HEAD_CHECK )
00332         {
00333             LOG( logmask, "%s: %u\n", curr->szFileLine, curr->size );
00334             _ctlvalidate( ALLOC_OFFSET(curr), "ctl_memory_dump" );
00335         }
00336         else
00337         {
00338             /* We can't trust any pointer between bad header checks */
00339             LOG( LOG_ERROR, "Bad memory node link\n" );
00340             break;
00341         }
00342     }
00343     return count;
00344 }
00345 #endif
00346 
00347 struct ctl_pool_base_block;
00348 struct ctl_pool_base_node;
00349 struct ctl_pool_base;
00353 struct ctl_pool_base_node
00354 {
00355     union
00356     {
00357         struct ctl_pool_base_node*  free;   
00358         ctl_pool_base*              pool;   
00359     } specialization;
00360     /* This is actually a union with a big, anonymous block of data */
00361     /* The data must be at a minimum the size of one pointer, or  */
00362     /* this won't work very well. */
00363 };
00371 struct ctl_pool_base_block
00372 {
00373     struct ctl_pool_base_block* next;   
00374     /*uint8                 data[1]; */
00375 };
00376 
00377 /* Keep track of pools that were initialized so they can be dumped later. */
00378 ctl_pool_base* ctl_pool_base_list = NULL;
00379 
00380 #ifndef NDEBUG
00381 
00384 size_t ctl_pool_dump( uint32 logmask )
00385 {
00386     size_t total = 0;
00387     sll_foreach_const(ctl_pool_base,poolList, ctl_pool_base_list, pool ) 
00388     {
00389         LOG( logmask, "%s: U:%u F:%u A:%u\n", pool->name, pool->unit, pool->cFree, pool->cAlloc );
00390         total++;
00391     }
00392     return total;
00393 }
00394 
00398 void ctl_destroy_all_pools( void )
00399 {
00400     while( NULL != ctl_pool_base_list )
00401     {
00402         ctl_pool_base* pool;
00403         sll_pop_front(ctl_pool_base,poolList, ctl_pool_base_list, pool );
00404         if( 0 != pool->cAlloc )
00405             LOG( LOG_ERROR, "Active Allocations in pool %s: U:%u F:%u A:%u\n", pool->name, pool->unit, pool->cFree, pool->cAlloc );
00406         ctl_pool_base_destroy( pool );
00407     }
00408 }
00409 #endif /* NDEBUG */
00410 
00417 void ctl_pool_base_init( ctl_pool_base* pool, size_t unitSize, size_t delta, const char* name )
00418 {
00419     assertobjptr(pool);
00420     assertconst(name,1);
00421 
00422     /* Initialize a pool */
00423     pool->freelist = NULL;
00424     pool->blocks = NULL;
00425     pool->poolList = NULL;
00426     pool->name = name;
00427     /* Units we deal with are allocated in values divisible by sizeof ctl_pool_base_node; setting aside room for one ctl_pool_base_node as well */
00428     pool->unit = unitSize;
00429     pool->delta = delta;
00430     pool->cFree = pool->cAlloc = 0;
00431 }
00432 
00438 void ctl_pool_base_grow( ctl_pool_base* pool, size_t delta )
00439 {
00440     /* Need to allocate a new block */
00441     struct ctl_pool_base_block* block;
00442     size_t unitSize = roundup(pool->unit, sizeof( struct ctl_pool_base_node )) + sizeof( struct ctl_pool_base_node );
00443     size_t size = sizeof(struct ctl_pool_base_block) + (unitSize * delta);
00444     ctl_malloc( block, size );
00445     /* Add to list of active pools */
00446     if( !pool->blocks )
00447         sll_push_front(ctl_pool_base,poolList, ctl_pool_base_list, pool );
00448     sll_push_front(struct ctl_pool_base_block,next, pool->blocks, block );
00449     {
00450         uint8* pCurr = (uint8*)block+size;
00451         size_t curr = delta;
00452         while( curr-- )
00453         {
00454             struct ctl_pool_base_node* pfree;
00455             pCurr -= unitSize;
00456             pfree = (struct ctl_pool_base_node*)pCurr;
00457             sll_push_front(struct ctl_pool_base_node,specialization.free, pool->freelist, pfree );
00458         }
00459         pool->cFree += delta;
00460     }
00461 }
00462 
00467 void ctl_pool_base_destroy( ctl_pool_base* pool )
00468 {
00469     /* Walk through each of our pool blocks, freeing the base pointer */
00470     struct ctl_pool_base_block* curr = pool->blocks;
00471     pool->blocks = NULL;
00472     while( curr )
00473     {
00474         struct ctl_pool_base_block* next = curr->next;
00475         ctl_free( curr );
00476         curr = next;
00477     }
00478     /* Remove from active pool list; this instance may be falling out of scope, or being freed */
00479     sll_erase(ctl_pool_base,poolList, ctl_pool_base_list, pool );
00480     memset(pool,0,sizeof(*pool));
00481 }
00482 
00488 void* ctl_pool_base_alloc( ctl_pool_base* pool )
00489 {
00490     struct ctl_pool_base_node* pfree = pool->freelist;
00491     if( NULL == pfree )
00492     {
00493         ctl_pool_base_grow( pool, pool->delta );
00494         pfree = pool->freelist;
00495     }
00496     pool->cFree--;
00497     pool->cAlloc++;
00498     sll_erase(struct ctl_pool_base_node,specialization.free, pool->freelist, pfree );
00499     ppDebug(pfree->specialization.pool = pool);
00500     return pfree+1;
00501 }
00502 
00508 void ctl_pool_base_free( ctl_pool_base* pool, void* ptr )
00509 {
00510     struct ctl_pool_base_node* pfree = (struct ctl_pool_base_node*)ptr-1;
00511     assertobjptr(pool);
00512     assertptr(ptr,4);
00513     
00514     /* We should not be expecting a free if nothing has been allocated from this pool */
00515     assert( pool->cAlloc > 0 );
00516     
00517     /* We stuck those pointers into the memory link nodes for a reason. */
00518     assert( pfree->specialization.pool == pool );
00519 
00520     /* Add it back to the free list */
00521     pool->cFree++;
00522     pool->cAlloc--;
00523     sll_push_front(struct ctl_pool_base_node,specialization.free, pool->freelist, pfree );
00524 }
00525 
00527 #define ctl_xenum(def)                              ppConcat(ctl_xenum_,def)
00528 #define ctl_xenum_space( size, delta )              ppConcat(ctl_mlspace_,size)
00529 #define ctl_xenum_object( type, delta )             ppConcat(ctl_mlspace_,type)
00530 #define ctl_xenum_label( label, type, delta )       ppConcat(ctl_mlspace_,label)
00531 #define ctl_xenum_term( type, delta )               ctl_mlspace_count
00532 
00534 #define ctl_xtab_size(def)                          ppConcat(ctl_xtab_size_,def)
00535 #define ctl_xtab_size_space( size, delta )          ctl_pool_base_entry( size, delta, "raw_" size ),
00536 #define ctl_xtab_size_object( type, delta )         
00537 #define ctl_xtab_size_label( label, type, delta )
00538 #define ctl_xtab_size_term( type, delta )           {0}
00539 
00541 #define ctl_xttab_type(def)                         ppConcat(ctl_xttab_type_,def)
00542 #define ctl_xttab_type_space( size, delta )         {0},
00543 #define ctl_xttab_type_object( type, delta )        ctl_pool_base_entry( size, delta, type ),
00544 #define ctl_xttab_type_label( label, type, delta )  ctl_pool_base_entry( sizeof(type), delta, label ),
00545 #define ctl_xttab_type_term( type, delta )          {0},
00546 
00548 #define ctl_xtab_type_space( size, delta )          void
00549 #define ctl_xtab_type_object( type, delta )         type
00550 #define ctl_xtab_type_label( label, type, delta )   type
00551 #define ctl_xtab_type_term( type, delta )           void
00552 
00554 #define CTL_META_LIST(def)\
00555     def( space(16, 64) )\
00556     def( space(32, 32) )\
00557     def( space(64, 16) )\
00558     def( space(96, 16) )\
00559     def( space(128, 16) )\
00560     def( space(192, 16) )\
00561     def( space(256, 8) )\
00562     def( space(384, 8) )\
00563     def( space(512, 8) )\
00564     def( space(640, 8) )\
00565     def( space(768, 4) )\
00566     def( space(1024, 4) )\
00567     def( space(1536, 4) )\
00568     def( space(2048, 4) )\
00569     def( space(3072, 4) )\
00570     def( space(4096, 4) )\
00571     def( space(6144, 3) )\
00572     def( space(8192, 2) )\
00573     def( object(type, 256) )\
00574     def( object(type, 256) )\
00575 
00576 
00577 #define ctl_mp_alloc_type(type)
00578 #define ctl_mp_free_type(type,ptr)
00579 #define ctl_mp_alloc_size(size)
00580 #define ctl_mp_realloc_size(size,ptr)
00581 #define ctl_mp_free_size(size,ptr)
00582 #define ctl_mp_free(ptr)
00583 #define ctl_mp_initialize()
00584 #define ctl_mp_make_report()
00585 #define ctl_mp_init_report()
00586 
00587 
00588 #else /* CTL_UNIT */
00589 
00590 #include "unit/unit.h"
00591 #include "pool.h"
00592 
00593 #define TEST_SIZE       3
00594 #define TEST_ARRAY_SIZE 32
00595 
00596 
00597 typedef struct Test
00598 {
00599     int value;
00600     const char* sz;
00601 } Test;
00602 ctl_fp_decl(Test,TEST_SIZE, TestPool );
00603 
00604 
00611 void Test_Malloc(void)
00612 {
00613     /* See if most of the malloc-based stuff works */
00614     {
00615         char* szDup = NULL;
00616         ctl_strdup(szDup,"CloneMe");
00617         Test_Error( !strcmp(szDup,"CloneMe") );
00618         Test_Error( ctl_size(szDup) == sizeof("CloneMe") );
00619         ctl_free(szDup);
00620         Test_Error( 0 == ctl_size(szDup) );
00621         Test_Error( NULL == szDup );
00622     }
00623     /* See if the fixed pool stuff works */
00624     {
00625         TestPool    scratchPool;
00626         Test* ptr;
00627         Test* ptr2;
00628         Test* ptr3;
00629         Test* ptr4;
00630         ctl_fp_init(TestPool, &scratchPool );
00631         ctl_fp_alloc(TestPool, &scratchPool, ptr );
00632         ctl_fp_alloc(TestPool, &scratchPool, ptr2 );
00633         ctl_fp_alloc(TestPool, &scratchPool, ptr3 );
00634         ctl_fp_alloc(TestPool, &scratchPool, ptr4 );
00635         Test_Error( NULL != ptr );
00636         Test_Error( NULL != ptr2 );
00637         Test_Error( NULL != ptr3 );
00638         Test_Error( NULL == ptr4 );
00639         ptr->value = 1;
00640         ptr->sz = "Spork";
00641         ptr2->value = 2;
00642         ptr2->sz = "Foon";
00643         ptr3->value = TEST_SIZE;
00644         ptr3->sz = "spam";
00645         Test_Error( false == ctl_fp_valid(TestPool, &scratchPool, "junk" ) );
00646         ctl_fp_free(TestPool, &scratchPool, ptr );
00647         ctl_fp_free(TestPool, &scratchPool, ptr2 );
00648         ctl_fp_free(TestPool, &scratchPool, ptr3 );
00649     }
00650     /* Harmless test */
00651     {
00652         ctl_pool_auto(TestPool,scratch,TEST_SIZE);
00653         ctl_pool_destroy(TestPool,&scratch);
00654     }
00655     {
00656         /* Do some test allocations */
00657         ctl_pool_auto(Test,scratch,TEST_SIZE);
00658         Test* ptr;
00659         Test* ptr2;
00660         Test* ptr3;
00661         Test* ptr4;
00662         ctl_pool_alloc(Test,&scratch,ptr);
00663         ctl_pool_alloc(Test,&scratch,ptr2);
00664         ctl_pool_alloc(Test,&scratch,ptr3);
00665         Test_Error( scratch.cFree == 0 );
00666         ctl_pool_alloc(Test,&scratch,ptr4);
00667         Test_Error( scratch.cFree == 2 );
00668         Test_Error( NULL != ptr );
00669         Test_Error( NULL != ptr2 );
00670         Test_Error( NULL != ptr3 );
00671         Test_Error( NULL != ptr4 );
00672         Test_Error( scratch.cAlloc == 4 );
00673 
00674         ptr->value = 1;
00675         ptr->sz = "Spork";
00676         ptr2->value = 2;
00677         ptr2->sz = "Foon";
00678         ptr3->value = TEST_SIZE;
00679         ptr3->sz = "spam";
00680         ptr4->value = TEST_SIZE;
00681         ptr4->sz = "Egg";
00682 
00683         ctl_pool_free(Test,&scratch,ptr);
00684         ctl_pool_free(Test,&scratch,ptr2);
00685         ctl_pool_free(Test,&scratch,ptr3);
00686         ctl_pool_free(Test,&scratch,ptr4);
00687         ctl_pool_destroy(Test,&scratch);
00688     }
00689 }
00690 
00691 #endif /* CTL_UNIT */

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6