00001 #include "niml_private.h"
00002
00003
00004
00005
00006
00007
00008
00009
00010 static void * (*user_malloc)(size_t) = NULL ;
00011 static void * (*user_realloc)(void *,size_t) = NULL ;
00012 static void (*user_free)(void *) = NULL ;
00013 static int use_userfunc = 0 ;
00014 static int ni_mall_used = 0 ;
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 int NI_malloc_replace( void *(*um)(size_t) ,
00032 void *(*ur)(void *,size_t) ,
00033 void (*uf)(void *) ){
00034
00035 if( ni_mall_used ||
00036 use_userfunc ||
00037 um == NULL ||
00038 ur == NULL ||
00039 uf == NULL ) return 0 ;
00040
00041 user_malloc = um ;
00042 user_realloc = ur ;
00043 user_free = uf ;
00044 use_userfunc = 1 ;
00045 return 1 ;
00046 }
00047
00048 #if defined(NIML_OLD_MALLOC) || defined(DONT_USE_MCW_MALLOC)
00049
00050
00051
00052
00053
00054 void * old_NI_malloc( size_t len )
00055 {
00056 void *p ;
00057 if( use_userfunc ){
00058 p = user_malloc(len) ; if( p != NULL ) memset(p,0,len) ;
00059 } else {
00060 p = calloc(1,len) ;
00061 }
00062 if( p == NULL ){
00063 fprintf(stderr,"** ERROR: old_NI_malloc() fails. Aauugghh!\n") ;
00064 NI_sleep(333); exit(1);
00065 }
00066 ni_mall_used = 1 ; return p ;
00067 }
00068
00069
00070
00071
00072
00073 void NI_free( void *p )
00074 {
00075 if( p != NULL ){
00076 if( use_userfunc ) user_free(p) ;
00077 else free(p) ;
00078 }
00079 ni_mall_used = 1 ;
00080 }
00081
00082
00083
00084
00085
00086 void * old_NI_realloc( void *p , size_t len )
00087 {
00088 void *q ;
00089
00090 if( use_userfunc ) q = user_realloc( p , len ) ;
00091 else q = realloc( p , len ) ;
00092 if( q == NULL && len > 0 ){
00093 fprintf(stderr,"** ERROR: old_NI_realloc() fails. Ooooogg!\n");
00094 NI_sleep(333); exit(1);
00095 }
00096 ni_mall_used = 1 ; return q ;
00097 }
00098
00099
00100
00101 char * NI_malloc_status (void){ return "disabled"; }
00102 void NI_malloc_dump (void){ return; }
00103 void NI_malloc_enable_tracking (void){ return; }
00104 int NI_malloc_tracking_enabled(void){ return 0; }
00105
00106
00107 #else
00108
00109
00110
00111 #define MAGIC ((char) 0xd7)
00112 #define NEXTRA (2*sizeof(int))
00113
00114 #undef UINT
00115 #define UINT unsigned int
00116
00117
00118
00119 typedef struct {
00120 void *pmt ;
00121
00122 size_t psz ;
00123 char *pfn ;
00124 int pln ;
00125 UINT pss ;
00126 } NI_mallitem ;
00127
00128
00129
00130 #undef SLOTS
00131 #define SLOTS 1031
00132
00133
00134
00135
00136
00137
00138
00139 static NI_mallitem ** htab = NULL ;
00140 static int * nhtab = NULL ;
00141 static UINT serial = 0 ;
00142
00143 #undef INLINE
00144 #ifdef __GNUC__
00145 # define INLINE inline
00146 #else
00147 # define INLINE
00148 #endif
00149
00150
00151
00152 static NI_mallitem * ptr_tracker( void * ) ;
00153 static NI_mallitem * find_empty_slot( int ) ;
00154 static void add_tracker( void * , size_t , char * , int ) ;
00155 static void * malloc_track( size_t , char * , int ) ;
00156 static void probe_track( NI_mallitem * , char *,int ) ;
00157 static void * realloc_track( NI_mallitem *, size_t , char *, int ) ;
00158 static void * calloc_track( size_t , size_t , char * , int ) ;
00159 static void free_track( NI_mallitem * ) ;
00160 static void qsort_intint( int, int *, int * ) ;
00161
00162 #undef malloc
00163 #undef realloc
00164 #undef calloc
00165 #undef free
00166
00167
00168
00169
00170
00171 static INLINE UINT mallkey( char *fred )
00172 {
00173 UINT q = (UINT) fred ;
00174
00175 q = ((q & 0xf0f0f0f0) >> 4)
00176 | ((q & 0x0f0f0f0f) << 4) ;
00177
00178 return q ;
00179 }
00180
00181
00182
00183
00184
00185
00186 static NI_mallitem * ptr_tracker( void *fred )
00187 {
00188 int jj,kk ;
00189
00190 if( fred == NULL ) return NULL ;
00191
00192 jj = mallkey((char *)fred) % SLOTS ;
00193
00194 if( htab[jj] == NULL ) return NULL ;
00195
00196 for( kk=0 ; kk < nhtab[jj] ; kk++ )
00197 if( htab[jj][kk].pmt == fred ) return (htab[jj]+kk) ;
00198
00199 return NULL ;
00200 }
00201
00202
00203
00204
00205 #define shift_tracker(fff) ptr_tracker( ((char *)(fff)) - NEXTRA )
00206
00207
00208
00209
00210
00211
00212 static NI_mallitem * find_empty_slot( int jj )
00213 {
00214 int kk ;
00215
00216 if( htab[jj] == NULL ){
00217 htab[jj] = (NI_mallitem *) malloc(sizeof(NI_mallitem)) ;
00218 nhtab[jj] = 1 ;
00219 kk = 0 ;
00220 htab[jj][0].pmt = NULL ;
00221 } else {
00222 for( kk=nhtab[jj]-1 ; kk >= 0 ; kk-- )
00223 if( htab[jj][kk].pmt == NULL ) break ;
00224
00225 if( kk < 0 ){
00226 kk = nhtab[jj] ; nhtab[jj]++ ;
00227 htab[jj] = (NI_mallitem *) realloc( htab[jj], sizeof(NI_mallitem)*nhtab[jj] ) ;
00228 htab[jj][kk].pmt = NULL ;
00229 }
00230 }
00231
00232 return (htab[jj]+kk) ;
00233 }
00234
00235
00236
00237
00238
00239
00240 static void add_tracker( void *fred , size_t n , char *fn , int ln )
00241 {
00242 int jj ;
00243 NI_mallitem *ip ;
00244
00245 if( fred == NULL ) return ;
00246
00247 jj = mallkey((char *)fred) % SLOTS ;
00248 ip = find_empty_slot(jj) ;
00249
00250
00251
00252 ip->pmt = fred ;
00253 ip->psz = n ;
00254 ip->pfn = fn ;
00255 ip->pln = ln ;
00256 ip->pss = ++serial ;
00257
00258 return ;
00259 }
00260
00261
00262
00263
00264
00265 static void * malloc_track( size_t n , char *fn , int ln )
00266 {
00267 char *fred ;
00268 size_t nn = n + 2*NEXTRA ;
00269 int ii ;
00270
00271 fred = (char *)malloc(nn) ;
00272 if( fred == NULL ) return NULL ;
00273
00274
00275
00276 memset( fred , MAGIC , NEXTRA ) ;
00277 memset( fred+(n+NEXTRA), MAGIC , NEXTRA ) ;
00278
00279 ni_mall_used = 1 ;
00280 add_tracker(fred,n,fn,ln) ;
00281 return (void *)(fred+NEXTRA) ;
00282 }
00283
00284
00285
00286
00287
00288 static void probe_track( NI_mallitem *ip , char *fn, int ln )
00289 {
00290 int ii ;
00291 size_t n ;
00292 char *fred ;
00293
00294 if( ip == NULL ) return ;
00295 fred = (char *) ip->pmt ; if( fred == NULL ) return ;
00296 n = ip->psz ;
00297
00298 for( ii=0 ; ii < NEXTRA ; ii++ )
00299 if( fred[ii] != MAGIC ){
00300 fprintf(stderr,"*** NI_malloc pre-corruption! "
00301 "serial=%u size=%u source=%s line#=%d\n",
00302 ip->pss,(unsigned int)ip->psz,ip->pfn,ip->pln ) ;
00303 if( fn != NULL ) fprintf(stderr," Caller=%s line#=%d\n",fn,ln) ;
00304 break ;
00305 }
00306
00307 for( ii=0 ; ii < NEXTRA ; ii++ )
00308 if( fred[n+NEXTRA+ii] != MAGIC ){
00309 fprintf(stderr,"*** NI_malloc post-corruption! "
00310 "serial=%u size=%u source=%s line#=%d\n",
00311 ip->pss,(unsigned int)ip->psz,ip->pfn,ip->pln ) ;
00312 if( fn != NULL ) fprintf(stderr," Caller=%s line#=%d\n",fn,ln) ;
00313 break ;
00314 }
00315
00316 return ;
00317 }
00318
00319
00320
00321
00322
00323 static void * realloc_track( NI_mallitem *ip, size_t n, char *fn, int ln )
00324 {
00325 char *nfred , *cfred ;
00326 size_t nn = n + 2*NEXTRA ;
00327 int ii , cjj,njj , kk ;
00328
00329 if( ip == NULL ) return NULL ;
00330
00331 probe_track(ip,fn,ln) ;
00332 cfred = (char *)ip->pmt ;
00333
00334 ni_mall_used = 1 ;
00335 nfred = (char *)realloc( (void *)cfred , nn ) ;
00336 if( nfred == NULL ) return NULL ;
00337
00338 memset( nfred , MAGIC , NEXTRA ) ;
00339 memset( nfred+(n+NEXTRA), MAGIC , NEXTRA ) ;
00340
00341 cjj = mallkey(cfred) % SLOTS ;
00342 njj = mallkey(nfred) % SLOTS ;
00343
00344 if( cjj == njj ){
00345
00346 ip->pmt = nfred ;
00347 ip->psz = n ;
00348 ip->pfn = fn ;
00349 ip->pln = ln ;
00350 ip->pss = ++serial ;
00351
00352 } else {
00353
00354 add_tracker( nfred , n , fn , ln ) ;
00355
00356 ip->pmt = NULL ;
00357 }
00358
00359 return (void *)(nfred+NEXTRA) ;
00360 }
00361
00362
00363
00364
00365
00366 static void * calloc_track( size_t n , size_t m , char *fn , int ln )
00367 {
00368 void *fred ;
00369 size_t nn = n*m ;
00370
00371 fred = malloc_track(nn,fn,ln) ; if( fred == NULL ) return NULL ;
00372 memset( fred , 0 , nn ) ;
00373 return fred ;
00374 }
00375
00376
00377
00378
00379
00380 static void free_track( NI_mallitem *ip )
00381 {
00382 char *cfred ;
00383
00384 if( ip == NULL ) return ;
00385 cfred = (char *) ip->pmt ;
00386 if( cfred == NULL ) return ;
00387
00388 probe_track(ip,NULL,0) ;
00389
00390 ni_mall_used = 1 ;
00391 free(cfred) ; ip->pmt = NULL ; return ;
00392 }
00393
00394
00395
00396
00397
00398
00399 static int use_tracking = 0 ;
00400
00401 char * NI_malloc_status(void)
00402 {
00403 static char buf[128] = "\0" ;
00404 int jj,kk , nptr=0 ; size_t nbyt=0 ;
00405
00406 if( ! use_tracking ) return "not enabled" ;
00407
00408 for( jj=0 ; jj < SLOTS ; jj++ ){
00409 for( kk=0 ; kk < nhtab[jj] ; kk++ ){
00410 if( htab[jj][kk].pmt != NULL ){
00411 probe_track( htab[jj]+kk , NULL,0 ) ;
00412 nptr++ ; nbyt += htab[jj][kk].psz ;
00413 }
00414 }
00415 }
00416
00417 sprintf(buf,"chunks=%d bytes=%u",nptr,(UINT)nbyt) ;
00418 return buf ;
00419 }
00420
00421
00422
00423
00424
00425 void NI_malloc_dump(void)
00426 {
00427 int ii,jj,kk ;
00428 char fname[32] , *str ;
00429 FILE *fp = NULL ;
00430 int nptr=0 ;
00431 int *ss , *jk ;
00432
00433 if( ! use_tracking ) return ;
00434
00435
00436
00437 for( ii=1 ; ii < 1000 ; ii++ ){
00438 sprintf(fname,"NI_malldump.%03d",ii) ;
00439 if( NI_is_file(fname) ) continue ;
00440 fp = fopen( fname , "w" ) ;
00441 if( fp == NULL ){
00442 fprintf(stderr,"** Unable to open file %s for malloc table dump!\n",
00443 fname ) ;
00444 return ;
00445 }
00446 break ;
00447 }
00448
00449 if( fp == NULL ){
00450 fprintf(stderr,"** Attempt to exceed 999 malloc table dump files!\n") ;
00451 return ;
00452 }
00453
00454
00455
00456 for( jj=0 ; jj < SLOTS ; jj++ ){
00457 for( kk=0 ; kk < nhtab[jj] ; kk++ ){
00458 if( htab[jj][kk].pmt != NULL ) nptr++ ;
00459 }
00460 }
00461
00462 if( nptr < 1 ){
00463 fprintf(fp ,"--- Nothing is malloc()-ed !? ---\n") ;
00464 fprintf(stderr,"--- Nothing is malloc()-ed !? ---\n") ;
00465 fclose(fp) ;
00466 }
00467
00468
00469
00470 ss = (int *) malloc(sizeof(int)*nptr) ;
00471 jk = (int *) malloc(sizeof(int)*nptr) ;
00472
00473 #define JBASE 32768
00474
00475
00476
00477 for( ii=jj=0 ; jj < SLOTS ; jj++ ){
00478 for( kk=0 ; kk < nhtab[jj] ; kk++ ){
00479 if( htab[jj][kk].pmt != NULL ){
00480 ss[ii] = htab[jj][kk].pss ;
00481 jk[ii] = JBASE*jj + kk ;
00482 ii++ ;
00483 }
00484 }
00485 }
00486
00487 qsort_intint( nptr , ss , jk ) ;
00488
00489
00490
00491 fprintf(fp, "MCW Malloc Table Dump:\n"
00492 "serial# size source file line# address hash(j,k)\n"
00493 "------- ---------- -------------------- ----- ---------- ---------\n") ;
00494
00495 for( ii=0 ; ii < nptr ; ii++ ){
00496 jj = jk[ii] / JBASE ;
00497 kk = jk[ii] % JBASE ;
00498 if( htab[jj][kk].pmt != NULL ){
00499 fprintf(fp,"%7u %10u %-20.30s %5d %10p %5d %3d",
00500 htab[jj][kk].pss , (unsigned int)htab[jj][kk].psz ,
00501 htab[jj][kk].pfn , htab[jj][kk].pln , htab[jj][kk].pmt ,
00502 jj,kk ) ;
00503 fprintf(fp,"\n") ;
00504 }
00505 else
00506 fprintf(fp,"*** Error at ii=%d jj=%d kk=%d\n",ii,jj,kk) ;
00507 }
00508
00509 free(ss) ; free(jk) ;
00510
00511
00512
00513 str = NI_malloc_status() ;
00514 fprintf(fp,"----- Summary: %s\n",str) ;
00515 fclose(fp) ;
00516
00517 fprintf(stderr,"** Malloc table dumped to file %s\n",fname) ;
00518 fprintf(stderr,"** Summary: %s\n",str) ;
00519
00520 return ;
00521 }
00522
00523
00524
00525
00526
00527 void NI_malloc_enable_tracking(void)
00528 {
00529 char *str ;
00530
00531 if( use_userfunc ) return ;
00532 ni_mall_used = 1 ;
00533
00534 if( use_tracking ) return ;
00535
00536 str = getenv("AFNI_NO_MCW_MALLOC") ;
00537 if( str == NULL )
00538 str = getenv("NIML_MALLOC_DISABLE") ;
00539
00540 use_tracking = 1 ;
00541 if( str!=NULL && ( *str=='y' || *str=='Y') ) use_tracking = 0 ;
00542
00543 if( use_tracking && htab == NULL ){
00544 int jj ;
00545 htab = (NI_mallitem **) malloc( SLOTS * sizeof(NI_mallitem *) ) ;
00546 nhtab = (int *) malloc( SLOTS * sizeof(int) ) ;
00547 for( jj=0 ; jj < SLOTS ; jj++ ){
00548 htab[jj] = NULL ; nhtab[jj] = 0 ;
00549 }
00550 }
00551
00552 return ;
00553 }
00554
00555
00556
00557
00558
00559 int NI_malloc_tracking_enabled(void)
00560 {
00561 return (use_tracking != 0) ;
00562 }
00563
00564
00565
00566
00567
00568 void * hidden_NI_malloc( size_t n , char *fnam , int lnum )
00569 {
00570 void *p ;
00571
00572 if( use_userfunc ){ p = user_malloc(n); if(p)memset(p,0,n); }
00573 else if( use_tracking ) p = calloc_track(1,n,fnam,lnum) ;
00574 else p = calloc(1,n) ;
00575
00576 if( p == NULL ){
00577 fprintf(stderr,"** ERROR: NI_malloc() fails. Aauugghh!\n") ;
00578 NI_sleep(333); exit(1);
00579 }
00580
00581 #ifdef NIML_DEBUG
00582 NI_dpr("hidden_NI_malloc: called from %s#%d\n",fnam,lnum) ;
00583 #endif
00584
00585 return p ;
00586 }
00587
00588
00589
00590
00591
00592 void * hidden_NI_realloc( void *fred , size_t n , char *fnam , int lnum )
00593 {
00594 NI_mallitem *ip ;
00595 void *q ;
00596
00597 if( fred == NULL )
00598 return hidden_NI_malloc( n , fnam , lnum ) ;
00599
00600 if( use_userfunc )
00601 q = user_realloc( fred , n ) ;
00602 else if( use_tracking && (ip=shift_tracker(fred)) != NULL )
00603 q = realloc_track( ip , n , fnam,lnum ) ;
00604 else
00605 q = realloc( fred , n ) ;
00606
00607 if( q == NULL && n > 0 ){
00608 fprintf(stderr,"** ERROR: NI_realloc() fails. Ooooogg!\n");
00609 NI_sleep(333); exit(1);
00610 }
00611
00612 #ifdef NIML_DEBUG
00613 NI_dpr("hidden_NI_realloc: called from %s#%d\n",fnam,lnum) ;
00614 #endif
00615
00616 return q ;
00617 }
00618
00619
00620
00621
00622
00623 void hidden_NI_free( void *fred , char *fnam , int lnum )
00624 {
00625 NI_mallitem *ip ;
00626
00627 if( fred == NULL ) return ;
00628
00629 if( use_userfunc ) user_free(fred) ;
00630 else if( use_tracking && (ip=shift_tracker(fred)) != NULL ) free_track( ip ) ;
00631 else free( fred ) ;
00632
00633 #ifdef NIML_DEBUG
00634 NI_dpr("hidden_NI_free: called from %s#%d\n",fnam,lnum) ;
00635 #endif
00636
00637 }
00638
00639
00640
00641
00642 static void isort_intint( int n , int * ar , int * iar )
00643 {
00644 register int j , p ;
00645 register int temp ;
00646 register int itemp ;
00647 register int * a = ar ;
00648 register int * ia = iar ;
00649
00650 if( n < 2 ) return ;
00651
00652 for( j=1 ; j < n ; j++ ){
00653
00654 if( a[j] < a[j-1] ){
00655 p = j ;
00656 temp = a[j] ; itemp = ia[j] ;
00657
00658 do{
00659 a[p] = a[p-1] ;
00660 ia[p] = ia[p-1] ;
00661 p-- ;
00662 } while( p > 0 && temp < a[p-1] ) ;
00663
00664 a[p] = temp ;
00665 ia[p] = itemp ;
00666 }
00667 }
00668 }
00669
00670
00671
00672
00673 #define QS_STACK 1024
00674 #define QS_SWAPF(x,y) ( temp=(x),(x)=(y),(y)= temp)
00675 #define QS_SWAPI(i,j) (itemp=(i),(i)=(j),(j)=itemp)
00676
00677 static void qsrec_intint( int n , int * ar , int * iar , int cutoff )
00678 {
00679 register int i , j ;
00680 register int temp , pivot ;
00681 register int itemp , ipivot ;
00682 register int * a = ar ;
00683 register int * ia = iar ;
00684
00685 int left , right , mst , stack[QS_STACK] , nnew ;
00686
00687
00688
00689 if( cutoff < 3 ) cutoff = 3 ;
00690 if( n < cutoff ) return ;
00691
00692
00693
00694 stack[0] = 0 ;
00695 stack[1] = n-1 ;
00696 mst = 2 ;
00697
00698
00699
00700 while( mst > 0 ){
00701 right = stack[--mst] ;
00702 left = stack[--mst] ;
00703
00704 i = ( left + right ) / 2 ;
00705
00706
00707
00708 if( a[left] > a[i] ){ QS_SWAPF(a[left] ,a[i] ); QS_SWAPI(ia[left] ,ia[i] ); }
00709 if( a[left] > a[right] ){ QS_SWAPF(a[left] ,a[right]); QS_SWAPI(ia[left] ,ia[right]); }
00710 if( a[i] > a[right] ){ QS_SWAPF(a[right],a[i] ); QS_SWAPI(ia[right],ia[i] ); }
00711
00712 pivot = a[i] ;
00713 a[i] = a[right] ;
00714 ipivot = ia[i] ;
00715 ia[i] = ia[right] ;
00716
00717 i = left ;
00718 j = right ;
00719
00720
00721
00722
00723 do{
00724 for( ; a[++i] < pivot ; ) ;
00725 for( ; a[--j] > pivot ; ) ;
00726
00727 if( j <= i ) break ;
00728
00729 QS_SWAPF( a[i] , a[j] ) ; QS_SWAPI( ia[i] , ia[j] ) ;
00730 } while( 1 ) ;
00731
00732
00733
00734 a[right] = a[i] ;
00735 a[i] = pivot ;
00736 ia[right] = ia[i] ;
00737 ia[i] = ipivot ;
00738
00739
00740
00741 nnew = 0 ;
00742 if( (i-left) > cutoff ){ stack[mst++] = left ; stack[mst++] = i-1 ; nnew++ ; }
00743 if( (right-i) > cutoff ){ stack[mst++] = i+1 ; stack[mst++] = right ; nnew++ ; }
00744
00745
00746
00747 if( nnew == 2 && stack[mst-3] - stack[mst-4] > stack[mst-1] - stack[mst-2] ){
00748 QS_SWAPI( stack[mst-4] , stack[mst-2] ) ;
00749 QS_SWAPI( stack[mst-3] , stack[mst-1] ) ;
00750 }
00751
00752 }
00753
00754 }
00755
00756
00757
00758
00759 #ifndef QS_CUTOFF
00760 #define QS_CUTOFF 10
00761 #endif
00762
00763 void qsort_intint( int n , int * a , int * ia )
00764 {
00765 qsrec_intint( n , a , ia , QS_CUTOFF ) ;
00766 isort_intint( n , a , ia ) ;
00767 return ;
00768 }
00769
00770
00771
00772
00773
00774 #ifdef NI_free
00775 #undef NI_free
00776 #endif
00777 void NI_free( void *p )
00778 {
00779 hidden_NI_free( p , (char *)"Nada" , 0 ) ;
00780 }
00781
00782 #endif