00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifdef _MSC_VER
00030
00031
00032 #endif
00033
00034
00035
00036 #include "nedmalloc.h"
00037 #ifdef WIN32
00038 #include <malloc.h>
00039 #endif
00040 #define MSPACES 1
00041 #define ONLY_MSPACES 1
00042 #ifndef USE_LOCKS
00043 #define USE_LOCKS 1
00044 #endif
00045 #define FOOTERS 1
00046 #undef DEBUG
00047 #ifdef _DEBUG
00048 #define DEBUG 1
00049 #else
00050 #define DEBUG 0
00051 #endif
00052 #ifdef NDEBUG
00053 #undef DEBUG
00054 #endif
00055
00056 #ifndef DEFAULT_GRANULARITY
00057 #define DEFAULT_GRANULARITY (1*1024*1024)
00058 #endif
00059
00060
00061
00062
00063 #include "malloc.c.h"
00064 #ifdef NDEBUG
00065 #undef DEBUG
00066 #endif
00067
00068
00069 #ifndef MAXTHREADSINPOOL
00070 #define MAXTHREADSINPOOL 16
00071 #endif
00072
00073 #ifndef THREADCACHEMAXCACHES
00074 #define THREADCACHEMAXCACHES 256
00075 #endif
00076
00077 #ifndef THREADCACHEMAX
00078 #define THREADCACHEMAX 8192
00079 #endif
00080 #if 0
00081
00082 #define THREADCACHEMAXBINS ((13-4)*2)
00083 #else
00084
00085 #define THREADCACHEMAXBINS (13-4)
00086 #endif
00087
00088 #ifndef THREADCACHEMAXFREESPACE
00089 #define THREADCACHEMAXFREESPACE (512*1024)
00090 #endif
00091
00092
00093 #ifdef WIN32
00094 #define TLSVAR DWORD
00095 #define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k))
00096 #define TLSFREE(k) (!TlsFree(k))
00097 #define TLSGET(k) TlsGetValue(k)
00098 #define TLSSET(k, a) (!TlsSetValue(k, a))
00099 #ifdef DEBUG
00100 static LPVOID ChkedTlsGetValue(DWORD idx)
00101 {
00102 LPVOID ret=TlsGetValue(idx);
00103 assert(S_OK==GetLastError());
00104 return ret;
00105 }
00106 #undef TLSGET
00107 #define TLSGET(k) ChkedTlsGetValue(k)
00108 #endif
00109 #else
00110 #define TLSVAR pthread_key_t
00111 #define TLSALLOC(k) pthread_key_create(k, 0)
00112 #define TLSFREE(k) pthread_key_delete(k)
00113 #define TLSGET(k) pthread_getspecific(k)
00114 #define TLSSET(k, a) pthread_setspecific(k, a)
00115 #endif
00116
00117 #if 0
00118
00119 #define mspace_malloc(p, s) malloc(s)
00120 #define mspace_realloc(p, m, s) realloc(m, s)
00121 #define mspace_calloc(p, n, s) calloc(n, s)
00122 #define mspace_free(p, m) free(m)
00123 #endif
00124
00125
00126 #if defined(__cplusplus)
00127 #if !defined(NO_NED_NAMESPACE)
00128 namespace nedalloc {
00129 #else
00130 extern "C" {
00131 #endif
00132 #endif
00133
00134 size_t nedblksize(void *mem) THROWSPEC
00135 {
00136 #if 0
00137
00138 return THREADCACHEMAX;
00139 #else
00140 if(mem)
00141 {
00142 mchunkptr p=mem2chunk(mem);
00143 assert(cinuse(p));
00144 if(cinuse(p))
00145 return chunksize(p)-overhead_for(p);
00146 }
00147 return 0;
00148 #endif
00149 }
00150
00151 void nedsetvalue(void *v) THROWSPEC { nedpsetvalue(0, v); }
00152 void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc(0, size); }
00153 void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc(0, no, size); }
00154 void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc(0, mem, size); }
00155 void nedfree(void *mem) THROWSPEC { nedpfree(0, mem); }
00156 void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign(0, alignment, bytes); }
00157 #if !NO_MALLINFO
00158 struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); }
00159 #endif
00160 int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); }
00161 int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); }
00162 void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); }
00163 size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); }
00164 void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); }
00165 void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); }
00166
00167 struct threadcacheblk_t;
00168 typedef struct threadcacheblk_t threadcacheblk;
00169 struct threadcacheblk_t
00170 {
00171 #ifdef FULLSANITYCHECKS
00172 unsigned int magic;
00173 #endif
00174 unsigned int lastUsed, size;
00175 threadcacheblk *next, *prev;
00176 };
00177 typedef struct threadcache_t
00178 {
00179 #ifdef FULLSANITYCHECKS
00180 unsigned int magic1;
00181 #endif
00182 int mymspace;
00183 long threadid;
00184 unsigned int mallocs, frees, successes;
00185 size_t freeInCache;
00186 threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2];
00187 #ifdef FULLSANITYCHECKS
00188 unsigned int magic2;
00189 #endif
00190 } threadcache;
00191 struct nedpool_t
00192 {
00193 MLOCK_T mutex;
00194 void *uservalue;
00195 int threads;
00196 threadcache *caches[THREADCACHEMAXCACHES];
00197 TLSVAR mycache;
00198 mstate m[MAXTHREADSINPOOL+1];
00199 };
00200 static nedpool syspool;
00201
00202 static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC
00203 {
00204 unsigned int topbit, size=(unsigned int)(_size>>4);
00205
00206
00207 #if defined(__GNUC__)
00208 topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size);
00209 #elif defined(_MSC_VER) && _MSC_VER>=1300
00210 {
00211 unsigned long bsrTopBit;
00212
00213 _BitScanReverse(&bsrTopBit, size);
00214
00215 topbit = bsrTopBit;
00216 }
00217 #else
00218 #if 0
00219 union {
00220 unsigned asInt[2];
00221 double asDouble;
00222 };
00223 int n;
00224
00225 asDouble = (double)size + 0.5;
00226 topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023;
00227 #else
00228 {
00229 unsigned int x=size;
00230 x = x | (x >> 1);
00231 x = x | (x >> 2);
00232 x = x | (x >> 4);
00233 x = x | (x >> 8);
00234 x = x | (x >>16);
00235 x = ~x;
00236 x = x - ((x >> 1) & 0x55555555);
00237 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
00238 x = (x + (x >> 4)) & 0x0F0F0F0F;
00239 x = x + (x << 8);
00240 x = x + (x << 16);
00241 topbit=31 - (x >> 24);
00242 }
00243 #endif
00244 #endif
00245 return topbit;
00246 }
00247
00248
00249 #ifdef FULLSANITYCHECKS
00250 static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC
00251 {
00252 assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1]));
00253 if(ptr[0] && ptr[1])
00254 {
00255 assert(nedblksize(ptr[0])>=sizeof(threadcacheblk));
00256 assert(nedblksize(ptr[1])>=sizeof(threadcacheblk));
00257 assert(*(unsigned int *) "NEDN"==ptr[0]->magic);
00258 assert(*(unsigned int *) "NEDN"==ptr[1]->magic);
00259 assert(!ptr[0]->prev);
00260 assert(!ptr[1]->next);
00261 if(ptr[0]==ptr[1])
00262 {
00263 assert(!ptr[0]->next);
00264 assert(!ptr[1]->prev);
00265 }
00266 }
00267 }
00268 static void tcfullsanitycheck(threadcache *tc) THROWSPEC
00269 {
00270 threadcacheblk **tcbptr=tc->bins;
00271 int n;
00272 for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
00273 {
00274 threadcacheblk *b, *ob=0;
00275 tcsanitycheck(tcbptr);
00276 for(b=tcbptr[0]; b; ob=b, b=b->next)
00277 {
00278 assert(*(unsigned int *) "NEDN"==b->magic);
00279 assert(!ob || ob->next==b);
00280 assert(!ob || b->prev==ob);
00281 }
00282 }
00283 }
00284 #endif
00285
00286 static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC
00287 {
00288 #ifdef FULLSANITYCHECKS
00289 tcfullsanitycheck(tc);
00290 #endif
00291 if(tc->freeInCache)
00292 {
00293 threadcacheblk **tcbptr=tc->bins;
00294 int n;
00295 for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
00296 {
00297 threadcacheblk **tcb=tcbptr+1;
00298
00299 for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; )
00300 {
00301 threadcacheblk *f=*tcb;
00302 size_t blksize=f->size;
00303 assert(blksize<=nedblksize(f));
00304 assert(blksize);
00305 #ifdef FULLSANITYCHECKS
00306 assert(*(unsigned int *) "NEDN"==(*tcb)->magic);
00307 #endif
00308 *tcb=(*tcb)->prev;
00309 if(*tcb)
00310 (*tcb)->next=0;
00311 else
00312 *tcbptr=0;
00313 tc->freeInCache-=blksize;
00314 assert((long) tc->freeInCache>=0);
00315 mspace_free(0, f);
00316
00317 }
00318 }
00319 }
00320 #ifdef FULLSANITYCHECKS
00321 tcfullsanitycheck(tc);
00322 #endif
00323 }
00324 static void DestroyCaches(nedpool *p) THROWSPEC
00325 {
00326 if(p->caches)
00327 {
00328 threadcache *tc;
00329 int n;
00330 for(n=0; n<THREADCACHEMAXCACHES; n++)
00331 {
00332 if((tc=p->caches[n]))
00333 {
00334 tc->frees++;
00335 RemoveCacheEntries(p, tc, 0);
00336 assert(!tc->freeInCache);
00337 tc->mymspace=-1;
00338 tc->threadid=0;
00339 mspace_free(0, tc);
00340 p->caches[n]=0;
00341 }
00342 }
00343 }
00344 }
00345
00346 static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC
00347 {
00348 threadcache *tc=0;
00349 int n, end;
00350 ACQUIRE_LOCK(&p->mutex);
00351 for(n=0; n<THREADCACHEMAXCACHES && p->caches[n]; n++);
00352 if(THREADCACHEMAXCACHES==n)
00353 {
00354 RELEASE_LOCK(&p->mutex);
00355 return 0;
00356 }
00357 tc=p->caches[n]=(threadcache *) mspace_calloc(p->m[0], 1, sizeof(threadcache));
00358 if(!tc)
00359 {
00360 RELEASE_LOCK(&p->mutex);
00361 return 0;
00362 }
00363 #ifdef FULLSANITYCHECKS
00364 tc->magic1=*(unsigned int *)"NEDMALC1";
00365 tc->magic2=*(unsigned int *)"NEDMALC2";
00366 #endif
00367 tc->threadid=(long)(size_t)CURRENT_THREAD;
00368 for(end=0; p->m[end]; end++);
00369 tc->mymspace=tc->threadid % end;
00370 RELEASE_LOCK(&p->mutex);
00371 if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort();
00372 return tc;
00373 }
00374
00375 static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROWSPEC
00376 {
00377 void *ret=0;
00378 unsigned int bestsize;
00379 unsigned int idx=size2binidx(*size);
00380 size_t blksize=0;
00381 threadcacheblk *blk, **binsptr;
00382 #ifdef FULLSANITYCHECKS
00383 tcfullsanitycheck(tc);
00384 #endif
00385
00386 bestsize=1<<(idx+4);
00387 #if 0
00388
00389 idx<<=1;
00390 if(*size>bestsize)
00391 {
00392 idx++;
00393 bestsize+=bestsize>>1;
00394 }
00395 if(*size>bestsize)
00396 {
00397 idx++;
00398 bestsize=1<<(4+(idx>>1));
00399 }
00400 #else
00401 if(*size>bestsize)
00402 {
00403 idx++;
00404 bestsize<<=1;
00405 }
00406 #endif
00407 assert(bestsize>=*size);
00408 if(*size<bestsize) *size=bestsize;
00409 assert(*size<=THREADCACHEMAX);
00410 assert(idx<=THREADCACHEMAXBINS);
00411 binsptr=&tc->bins[idx*2];
00412
00413 blk=*binsptr;
00414 if(!blk || blk->size<*size)
00415 {
00416 if(idx<THREADCACHEMAXBINS)
00417 {
00418 idx++;
00419 binsptr+=2;
00420 blk=*binsptr;
00421 }
00422 }
00423 if(blk)
00424 {
00425 blksize=blk->size;
00426 assert(nedblksize(blk)>=blksize);
00427 assert(blksize>=*size);
00428 if(blk->next)
00429 blk->next->prev=0;
00430 *binsptr=blk->next;
00431 if(!*binsptr)
00432 binsptr[1]=0;
00433 #ifdef FULLSANITYCHECKS
00434 blk->magic=0;
00435 #endif
00436 assert(binsptr[0]!=blk && binsptr[1]!=blk);
00437 assert(nedblksize(blk)>=sizeof(threadcacheblk) && nedblksize(blk)<=THREADCACHEMAX+CHUNK_OVERHEAD);
00438
00439 ret=(void *) blk;
00440 }
00441 ++tc->mallocs;
00442 if(ret)
00443 {
00444 assert(blksize>=*size);
00445 ++tc->successes;
00446 tc->freeInCache-=blksize;
00447 assert((long) tc->freeInCache>=0);
00448 }
00449 #if defined(DEBUG) && 0
00450 if(!(tc->mallocs & 0xfff))
00451 {
00452 printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs,
00453 (float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache);
00454 }
00455 #endif
00456 #ifdef FULLSANITYCHECKS
00457 tcfullsanitycheck(tc);
00458 #endif
00459 return ret;
00460 }
00461 static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspace) THROWSPEC
00462 {
00463 unsigned int age=THREADCACHEMAXFREESPACE/8192;
00464
00465 while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
00466 {
00467 RemoveCacheEntries(p, tc, age);
00468
00469 age>>=1;
00470 }
00471
00472 }
00473 static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *mem, size_t size) THROWSPEC
00474 {
00475 unsigned int bestsize;
00476 unsigned int idx=size2binidx(size);
00477 threadcacheblk **binsptr, *tck=(threadcacheblk *) mem;
00478 assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
00479 #ifdef DEBUG
00480 {
00481 mchunkptr p = mem2chunk(mem);
00482 mstate fm = get_mstate_for(p);
00483 if (!ok_magic(fm)) {
00484 USAGE_ERROR_ACTION(fm, p);
00485 return;
00486 }
00487 }
00488 #endif
00489 #ifdef FULLSANITYCHECKS
00490 tcfullsanitycheck(tc);
00491 #endif
00492
00493 bestsize=1<<(idx+4);
00494 #if 0
00495
00496 idx<<=1;
00497 if(size>bestsize)
00498 {
00499 unsigned int biggerbestsize=bestsize+bestsize<<1;
00500 if(size>=biggerbestsize)
00501 {
00502 idx++;
00503 bestsize=biggerbestsize;
00504 }
00505 }
00506 #endif
00507 if(bestsize!=size)
00508 size=bestsize;
00509 binsptr=&tc->bins[idx*2];
00510 assert(idx<=THREADCACHEMAXBINS);
00511 if(tck==*binsptr)
00512 {
00513 fprintf(stderr, "Attempt to free already freed memory block %p - aborting!\n", tck);
00514 abort();
00515 }
00516 #ifdef FULLSANITYCHECKS
00517 tck->magic=*(unsigned int *) "NEDN";
00518 #endif
00519 tck->lastUsed=++tc->frees;
00520 tck->size=(unsigned int) size;
00521 tck->next=*binsptr;
00522 tck->prev=0;
00523 if(tck->next)
00524 tck->next->prev=tck;
00525 else
00526 binsptr[1]=tck;
00527 assert(!*binsptr || (*binsptr)->size==tck->size);
00528 *binsptr=tck;
00529 assert(tck==tc->bins[idx*2]);
00530 assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck);
00531
00532 tc->freeInCache+=size;
00533 #ifdef FULLSANITYCHECKS
00534 tcfullsanitycheck(tc);
00535 #endif
00536 #if 1
00537 if(tc->freeInCache>=THREADCACHEMAXFREESPACE)
00538 ReleaseFreeInCache(p, tc, mymspace);
00539 #endif
00540 }
00541
00542
00543
00544
00545 static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC
00546 {
00547 ensure_initialization();
00548 ACQUIRE_MALLOC_GLOBAL_LOCK();
00549 if(p->threads) goto done;
00550 if(INITIAL_LOCK(&p->mutex)) goto err;
00551 if(TLSALLOC(&p->mycache)) goto err;
00552 if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
00553 p->m[0]->extp=p;
00554 p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
00555 done:
00556 RELEASE_MALLOC_GLOBAL_LOCK();
00557 return 1;
00558 err:
00559 if(threads<0)
00560 abort();
00561 DestroyCaches(p);
00562 if(p->m[0])
00563 {
00564 destroy_mspace(p->m[0]);
00565 p->m[0]=0;
00566 }
00567 if(p->mycache)
00568 {
00569 if(TLSFREE(p->mycache)) abort();
00570 p->mycache=0;
00571 }
00572 RELEASE_MALLOC_GLOBAL_LOCK();
00573 return 0;
00574 }
00575 static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, size_t size) THROWSPEC
00576 {
00577
00578
00579
00580 int n, end;
00581 for(n=end=*lastUsed+1; p->m[n]; end=++n)
00582 {
00583 if(TRY_LOCK(&p->m[n]->mutex)) goto found;
00584 }
00585 for(n=0; n<*lastUsed && p->m[n]; n++)
00586 {
00587 if(TRY_LOCK(&p->m[n]->mutex)) goto found;
00588 }
00589 if(end<p->threads)
00590 {
00591 mstate temp;
00592 if(!(temp=(mstate) create_mspace(size, 1)))
00593 goto badexit;
00594
00595 ACQUIRE_LOCK(&p->mutex);
00596 while(p->m[end] && end<p->threads)
00597 end++;
00598 if(end>=p->threads)
00599 {
00600 RELEASE_LOCK(&p->mutex);
00601 destroy_mspace((mspace) temp);
00602 goto badexit;
00603 }
00604
00605
00606 *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp;
00607 ACQUIRE_LOCK(&p->m[end]->mutex);
00608
00609 RELEASE_LOCK(&p->mutex);
00610 n=end;
00611 goto found;
00612 }
00613
00614 badexit:
00615 ACQUIRE_LOCK(&p->m[*lastUsed]->mutex);
00616 return p->m[*lastUsed];
00617 found:
00618 *lastUsed=n;
00619 if(tc)
00620 tc->mymspace=n;
00621 else
00622 {
00623 if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort();
00624 }
00625 return p->m[n];
00626 }
00627
00628 nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC
00629 {
00630 nedpool *ret;
00631 if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) return 0;
00632 if(!InitPool(ret, capacity, threads))
00633 {
00634 nedpfree(0, ret);
00635 return 0;
00636 }
00637 return ret;
00638 }
00639 void neddestroypool(nedpool *p) THROWSPEC
00640 {
00641 int n;
00642 ACQUIRE_LOCK(&p->mutex);
00643 DestroyCaches(p);
00644 for(n=0; p->m[n]; n++)
00645 {
00646 destroy_mspace(p->m[n]);
00647 p->m[n]=0;
00648 }
00649 RELEASE_LOCK(&p->mutex);
00650 if(TLSFREE(p->mycache)) abort();
00651 nedpfree(0, p);
00652 }
00653
00654 void nedpsetvalue(nedpool *p, void *v) THROWSPEC
00655 {
00656 if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
00657 p->uservalue=v;
00658 }
00659 void *nedgetvalue(nedpool **p, void *mem) THROWSPEC
00660 {
00661 nedpool *np=0;
00662 mchunkptr mcp=mem2chunk(mem);
00663 mstate fm;
00664 if(!(is_aligned(chunk2mem(mcp))) && mcp->head != FENCEPOST_HEAD) return 0;
00665 if(!cinuse(mcp)) return 0;
00666 if(!next_pinuse(mcp)) return 0;
00667 if(!is_mmapped(mcp) && !pinuse(mcp))
00668 {
00669 if(next_chunk(prev_chunk(mcp))!=mcp) return 0;
00670 }
00671 fm=get_mstate_for(mcp);
00672 if(!ok_magic(fm)) return 0;
00673 if(!ok_address(fm, mcp)) return 0;
00674 if(!fm->extp) return 0;
00675 np=(nedpool *) fm->extp;
00676 if(p) *p=np;
00677 return np->uservalue;
00678 }
00679
00680 void neddisablethreadcache(nedpool *p) THROWSPEC
00681 {
00682 int mycache;
00683 if(!p)
00684 {
00685 p=&syspool;
00686 if(!syspool.threads) InitPool(&syspool, 0, -1);
00687 }
00688 mycache=(int)(size_t) TLSGET(p->mycache);
00689 if(!mycache)
00690 {
00691 if(TLSSET(p->mycache, (void *)-1)) abort();
00692 }
00693 else if(mycache>0)
00694 {
00695 threadcache *tc=p->caches[mycache-1];
00696 #if defined(DEBUG)
00697 printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n",
00698 100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs);
00699 #endif
00700 if(TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort();
00701 tc->frees++;
00702 RemoveCacheEntries(p, tc, 0);
00703 assert(!tc->freeInCache);
00704 tc->mymspace=-1;
00705 tc->threadid=0;
00706 mspace_free(0, p->caches[mycache-1]);
00707 p->caches[mycache-1]=0;
00708 }
00709 }
00710
00711 #define GETMSPACE(m,p,tc,ms,s,action) \
00712 do \
00713 { \
00714 mstate m = GetMSpace((p),(tc),(ms),(s)); \
00715 action; \
00716 RELEASE_LOCK(&m->mutex); \
00717 } while (0)
00718
00719 static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC
00720 {
00721 mstate m=p->m[mymspace];
00722 assert(m);
00723 if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);\
00724
00725 return m;
00726 }
00727 static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC
00728 {
00729 int mycache;
00730 if(size && *size<sizeof(threadcacheblk)) *size=sizeof(threadcacheblk);
00731 if(!*p)
00732 {
00733 *p=&syspool;
00734 if(!syspool.threads) InitPool(&syspool, 0, -1);
00735 }
00736 mycache=(int)(size_t) TLSGET((*p)->mycache);
00737 if(mycache>0)
00738 {
00739 *tc=(*p)->caches[mycache-1];
00740 *mymspace=(*tc)->mymspace;
00741 }
00742 else if(!mycache)
00743 {
00744 *tc=AllocCache(*p);
00745 if(!*tc)
00746 {
00747 if(TLSSET((*p)->mycache, (void *)-1)) abort();
00748 *mymspace=0;
00749 }
00750 else
00751 *mymspace=(*tc)->mymspace;
00752 }
00753 else
00754 {
00755 *tc=0;
00756 *mymspace=-mycache-1;
00757 }
00758 assert(*mymspace>=0);
00759 assert((long)(size_t)CURRENT_THREAD==(*tc)->threadid);
00760 #ifdef FULLSANITYCHECKS
00761 if(*tc)
00762 {
00763 if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2)
00764 {
00765 abort();
00766 }
00767 }
00768 #endif
00769 }
00770
00771 void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
00772 {
00773 void *ret=0;
00774 threadcache *tc;
00775 int mymspace;
00776 GetThreadCache(&p, &tc, &mymspace, &size);
00777 #if THREADCACHEMAX
00778 if(tc && size<=THREADCACHEMAX)
00779 {
00780 ret=threadcache_malloc(p, tc, &size);
00781 }
00782 #endif
00783 if(!ret)
00784 {
00785 GETMSPACE(m, p, tc, mymspace, size,
00786 ret=mspace_malloc(m, size));
00787 }
00788 return ret;
00789 }
00790 void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
00791 {
00792 size_t rsize=size*no;
00793 void *ret=0;
00794 threadcache *tc;
00795 int mymspace;
00796 GetThreadCache(&p, &tc, &mymspace, &rsize);
00797 #if THREADCACHEMAX
00798 if(tc && rsize<=THREADCACHEMAX)
00799 {
00800 if((ret=threadcache_malloc(p, tc, &rsize)))
00801 memset(ret, 0, rsize);
00802 }
00803 #endif
00804 if(!ret)
00805 {
00806 GETMSPACE(m, p, tc, mymspace, rsize,
00807 ret=mspace_calloc(m, 1, rsize));
00808 }
00809 return ret;
00810 }
00811 void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC
00812 {
00813 void *ret=0;
00814 threadcache *tc;
00815 int mymspace;
00816 if(!mem) return nedpmalloc(p, size);
00817 GetThreadCache(&p, &tc, &mymspace, &size);
00818 #if THREADCACHEMAX
00819 if(tc && size && size<=THREADCACHEMAX)
00820 {
00821 size_t memsize=nedblksize(mem);
00822 assert(memsize);
00823 if((ret=threadcache_malloc(p, tc, &size)))
00824 {
00825 memcpy(ret, mem, memsize<size ? memsize : size);
00826 if(memsize<=THREADCACHEMAX)
00827 threadcache_free(p, tc, mymspace, mem, memsize);
00828 else
00829 mspace_free(0, mem);
00830 }
00831 }
00832 #endif
00833 if(!ret)
00834 {
00835
00836 ret=mspace_realloc(0, mem, size);
00837 }
00838 return ret;
00839 }
00840 void nedpfree(nedpool *p, void *mem) THROWSPEC
00841 {
00842
00843 threadcache *tc;
00844 int mymspace;
00845 size_t memsize;
00846 assert(mem);
00847 GetThreadCache(&p, &tc, &mymspace, 0);
00848 #if THREADCACHEMAX
00849 memsize=nedblksize(mem);
00850 assert(memsize);
00851 if(mem && tc && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
00852 threadcache_free(p, tc, mymspace, mem, memsize);
00853 else
00854 #endif
00855 mspace_free(0, mem);
00856 }
00857 void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
00858 {
00859 void *ret;
00860 threadcache *tc;
00861 int mymspace;
00862 GetThreadCache(&p, &tc, &mymspace, &bytes);
00863 {
00864 GETMSPACE(m, p, tc, mymspace, bytes,
00865 ret=mspace_memalign(m, alignment, bytes));
00866 }
00867 return ret;
00868 }
00869 #if !NO_MALLINFO
00870 struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC
00871 {
00872 int n;
00873 struct mallinfo ret={0};
00874 if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
00875 for(n=0; p->m[n]; n++)
00876 {
00877 struct mallinfo t=mspace_mallinfo(p->m[n]);
00878 ret.arena+=t.arena;
00879 ret.ordblks+=t.ordblks;
00880 ret.hblkhd+=t.hblkhd;
00881 ret.usmblks+=t.usmblks;
00882 ret.uordblks+=t.uordblks;
00883 ret.fordblks+=t.fordblks;
00884 ret.keepcost+=t.keepcost;
00885 }
00886 return ret;
00887 }
00888 #endif
00889 int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
00890 {
00891 return mspace_mallopt(parno, value);
00892 }
00893 int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
00894 {
00895 int n, ret=0;
00896 if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
00897 for(n=0; p->m[n]; n++)
00898 {
00899 ret+=mspace_trim(p->m[n], pad);
00900 }
00901 return ret;
00902 }
00903 void nedpmalloc_stats(nedpool *p) THROWSPEC
00904 {
00905 int n;
00906 if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
00907 for(n=0; p->m[n]; n++)
00908 {
00909 mspace_malloc_stats(p->m[n]);
00910 }
00911 }
00912 size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
00913 {
00914 size_t ret=0;
00915 int n;
00916 if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
00917 for(n=0; p->m[n]; n++)
00918 {
00919 ret+=mspace_footprint(p->m[n]);
00920 }
00921 return ret;
00922 }
00923 void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC
00924 {
00925 void **ret;
00926 threadcache *tc;
00927 int mymspace;
00928 GetThreadCache(&p, &tc, &mymspace, &elemsize);
00929 GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
00930 ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
00931 return ret;
00932 }
00933 void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
00934 {
00935 void **ret;
00936 threadcache *tc;
00937 int mymspace;
00938 size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t));
00939 if(!adjustedsizes) return 0;
00940 for(i=0; i<elems; i++)
00941 adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
00942 GetThreadCache(&p, &tc, &mymspace, 0);
00943 GETMSPACE(m, p, tc, mymspace, 0,
00944 ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
00945 return ret;
00946 }
00947
00948 #if defined(__cplusplus)
00949 }
00950 #endif