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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #if !defined(q_malloc) && (defined F_MALLOC)
00040
00041 #include <string.h>
00042 #include <stdlib.h>
00043
00044 #include "f_malloc.h"
00045 #include "../dprint.h"
00046 #include "../globals.h"
00047 #include "../statistics.h"
00048 #include "../compiler_opt.h"
00049 #include "../bit_scan.h"
00050
00051
00052
00053
00054 #define FRAG_NEXT(f) \
00055 ((struct fm_frag*)((char*)(f)+sizeof(struct fm_frag)+(f)->size ))
00056
00057 #define FRAG_OVERHEAD (sizeof(struct fm_frag))
00058 #define INIT_OVERHEAD \
00059 (ROUNDUP(sizeof(struct fm_block))+sizeof(struct fm_frag))
00060
00061
00062
00063
00064 #define ROUNDTO_MASK (~((unsigned long)ROUNDTO-1))
00065 #define ROUNDUP(s) (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
00066 #define ROUNDDOWN(s) ((s)&ROUNDTO_MASK)
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #define GET_HASH(s) ( ((unsigned long)(s)<=F_MALLOC_OPTIMIZE)?\
00077 (unsigned long)(s)/ROUNDTO: \
00078 F_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
00079 F_MALLOC_OPTIMIZE_FACTOR+1 )
00080
00081 #define UN_HASH(h) ( ((unsigned long)(h)<=(F_MALLOC_OPTIMIZE/ROUNDTO))?\
00082 (unsigned long)(h)*ROUNDTO: \
00083 1UL<<((unsigned long)(h)-F_MALLOC_OPTIMIZE/ROUNDTO+\
00084 F_MALLOC_OPTIMIZE_FACTOR-1)\
00085 )
00086
00087 #ifdef F_MALLOC_HASH_BITMAP
00088
00089 #define fm_bmp_set(qm, b) \
00090 do{ \
00091 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] |= \
00092 1UL<<((b)%FM_HASH_BMP_BITS); \
00093 }while(0)
00094
00095 #define fm_bmp_reset(qm, b) \
00096 do{ \
00097 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] &= \
00098 ~(1UL<<((b)%FM_HASH_BMP_BITS)); \
00099 }while(0)
00100
00101
00102 #define fm_bmp_is_set(qm, b) \
00103 ((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))
00104
00105 inline static int fm_bmp_first_set(struct fm_block* qm, int start)
00106 {
00107 int bmp_idx;
00108 int bit;
00109 int r;
00110 fm_hash_bitmap_t test_val;
00111 fm_hash_bitmap_t v;
00112
00113 bmp_idx=start/FM_HASH_BMP_BITS;
00114 bit=start%FM_HASH_BMP_BITS;
00115 test_val=1UL <<((unsigned long)bit);
00116 if (qm->free_bitmap[bmp_idx] & test_val)
00117 return start;
00118 else if (qm->free_bitmap[bmp_idx] & ~(test_val-1)){
00119 #if 0
00120 test_val<<=1;
00121 for (r=bit+1; r<FM_HASH_BMP_BITS; r++, test_val<<=1){
00122 if (qm->free_bitmap[bmp_idx] & test_val)
00123 return (start-bit+r);
00124 }
00125 #endif
00126 v=qm->free_bitmap[bmp_idx]>>(bit+1);
00127 return start+1+bit_scan_forward((unsigned long)v);
00128 }
00129 for (r=bmp_idx+1;r<FM_HASH_BMP_SIZE; r++){
00130 if (qm->free_bitmap[r]){
00131
00132 return r*FM_HASH_BMP_BITS+
00133 bit_scan_forward((unsigned long)qm->free_bitmap[r]);
00134 }
00135 }
00136
00137 return -1;
00138 }
00139 #endif
00140
00141
00142
00143
00144 #define FRAG_MARK_USED(f)
00145 #define FRAG_CLEAR_USED(f)
00146 #define FRAG_WAS_USED(f) (1)
00147
00148
00149
00150
00151
00152 #define MEM_FRAG_AVOIDANCE
00153
00154
00155
00156 #if 0
00157 inline static unsigned long big_hash_idx(unsigned long s)
00158 {
00159 unsigned long idx;
00160
00161
00162
00163
00164 idx=sizeof(long)*8-1;
00165 for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
00166 return idx;
00167 }
00168 #else
00169 #define big_hash_idx(s) ((unsigned long)bit_scan_reverse((unsigned long)(s)))
00170 #endif
00171
00172
00173 #ifdef DBG_F_MALLOC
00174 #define ST_CHECK_PATTERN 0xf0f0f0f0
00175 #define END_CHECK_PATTERN1 0xc0c0c0c0
00176 #define END_CHECK_PATTERN2 0xabcdefed
00177 #endif
00178
00179
00180
00181 static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
00182 {
00183 struct fm_frag** f;
00184 int hash;
00185
00186 hash=GET_HASH(frag->size);
00187 f=&(qm->free_hash[hash].first);
00188 if (frag->size > F_MALLOC_OPTIMIZE){
00189
00190
00191 for(; *f; f=&((*f)->u.nxt_free)){
00192 if (frag->size <= (*f)->size) break;
00193 }
00194 }
00195
00196
00197 frag->u.nxt_free=*f;
00198 *f=frag;
00199 qm->free_hash[hash].no++;
00200 #ifdef F_MALLOC_HASH_BITMAP
00201 fm_bmp_set(qm, hash);
00202 #endif
00203 }
00204
00205
00206
00207
00208 static inline
00209 #ifdef DBG_F_MALLOC
00210 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
00211 unsigned long size,
00212 const char* file, const char* func, unsigned int line)
00213 #else
00214 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
00215 unsigned long size)
00216 #endif
00217 {
00218 unsigned long rest;
00219 struct fm_frag* n;
00220
00221 rest=frag->size-size;
00222 #ifdef MEM_FRAG_AVOIDANCE
00223 if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))||
00224 (rest>=(FRAG_OVERHEAD+size))){
00225 #else
00226 if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
00227 #endif
00228 frag->size=size;
00229
00230 n=FRAG_NEXT(frag);
00231 n->size=rest-FRAG_OVERHEAD;
00232 FRAG_CLEAR_USED(n);
00233 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00234 qm->real_used+=FRAG_OVERHEAD;
00235 #endif
00236 #ifdef DBG_F_MALLOC
00237
00238 n->file=file;
00239 n->func="frag. from fm_malloc";
00240 n->line=line;
00241 n->check=ST_CHECK_PATTERN;
00242 #endif
00243
00244 fm_insert_free(qm, n);
00245 }else{
00246
00247 }
00248 }
00249
00250
00251
00252
00253 struct fm_block* fm_malloc_init(char* address, unsigned long size)
00254 {
00255 char* start;
00256 char* end;
00257 struct fm_block* qm;
00258 unsigned long init_overhead;
00259
00260
00261 start=(char*)ROUNDUP((unsigned long) address);
00262 LM_DBG("F_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
00263 F_MALLOC_OPTIMIZE, F_MALLOC_OPTIMIZE/ROUNDTO);
00264 LM_DBG("F_HASH_SIZE=%lu, fm_block size=%lu\n",
00265 F_HASH_SIZE, (long)sizeof(struct fm_block));
00266 LM_DBG("params (%p, %lu), start=%p\n", address, size, start);
00267
00268 if (size<(unsigned long)(start-address)) return 0;
00269 size-=(start-address);
00270 if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
00271 size=ROUNDDOWN(size);
00272
00273 init_overhead=INIT_OVERHEAD;
00274
00275
00276 if (size < init_overhead)
00277 {
00278
00279 return 0;
00280 }
00281 end=start+size;
00282 qm=(struct fm_block*)start;
00283 memset(qm, 0, sizeof(struct fm_block));
00284 qm->size=size;
00285 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00286 qm->real_used=init_overhead;
00287 qm->max_real_used=qm->real_used;
00288 #endif
00289 size-=init_overhead;
00290
00291 qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block)));
00292 qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
00293
00294 qm->first_frag->size=size;
00295 qm->last_frag->size=0;
00296
00297 #ifdef DBG_F_MALLOC
00298 qm->first_frag->check=ST_CHECK_PATTERN;
00299 qm->last_frag->check=END_CHECK_PATTERN1;
00300 #endif
00301
00302
00303
00304 fm_insert_free(qm, qm->first_frag);
00305
00306
00307 return qm;
00308 }
00309
00310
00311
00312 #ifdef DBG_F_MALLOC
00313 void* fm_malloc(struct fm_block* qm, unsigned long size,
00314 const char* file, const char* func, unsigned int line)
00315 #else
00316 void* fm_malloc(struct fm_block* qm, unsigned long size)
00317 #endif
00318 {
00319 struct fm_frag** f;
00320 struct fm_frag* frag;
00321 int hash;
00322
00323 #ifdef DBG_F_MALLOC
00324 LM_DBG("params (%p, %lu), called from %s: %s(%d)\n", qm, size, file, func,
00325 line);
00326 #endif
00327
00328 size=ROUNDUP(size);
00329
00330
00331
00332
00333
00334 #ifdef F_MALLOC_HASH_BITMAP
00335 hash=fm_bmp_first_set(qm, GET_HASH(size));
00336 if (likely(hash>=0)){
00337 f=&(qm->free_hash[hash].first);
00338 if (likely(hash<=F_MALLOC_OPTIMIZE))
00339 goto found;
00340 for(;(*f); f=&((*f)->u.nxt_free))
00341 if ((*f)->size>=size) goto found;
00342 }
00343 #else
00344 for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
00345 f=&(qm->free_hash[hash].first);
00346 #if 0
00347 if (likely(hash<=F_MALLOC_OPTIMIZE))
00348 goto found;
00349 #endif
00350 for(;(*f); f=&((*f)->u.nxt_free))
00351 if ((*f)->size>=size) goto found;
00352
00353 }
00354 #endif
00355
00356 return 0;
00357
00358 found:
00359
00360
00361 frag=*f;
00362 *f=frag->u.nxt_free;
00363 frag->u.nxt_free=0;
00364 qm->free_hash[hash].no--;
00365 #ifdef F_MALLOC_HASH_BITMAP
00366 if (qm->free_hash[hash].no==0)
00367 fm_bmp_reset(qm, hash);
00368 #endif
00369
00370
00371
00372 #ifdef DBG_F_MALLOC
00373 fm_split_frag(qm, frag, size, file, func, line);
00374
00375 frag->file=file;
00376 frag->func=func;
00377 frag->line=line;
00378 frag->check=ST_CHECK_PATTERN;
00379 LM_DBG("params(%p, %lu), returns address %p \n", qm, size,
00380 (char*)frag+sizeof(struct fm_frag));
00381 #else
00382 fm_split_frag(qm, frag, size);
00383 #endif
00384 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00385 qm->real_used+=frag->size;
00386 qm->used+=frag->size;
00387 if (qm->max_real_used<qm->real_used)
00388 qm->max_real_used=qm->real_used;
00389 #endif
00390 FRAG_MARK_USED(frag);
00391 return (char*)frag+sizeof(struct fm_frag);
00392 }
00393
00394
00395
00396 #ifdef DBG_F_MALLOC
00397 void fm_free(struct fm_block* qm, void* p, const char* file, const char* func,
00398 unsigned int line)
00399 #else
00400 void fm_free(struct fm_block* qm, void* p)
00401 #endif
00402 {
00403 struct fm_frag* f;
00404 unsigned long size;
00405
00406 #ifdef DBG_F_MALLOC
00407 LM_DBG("params(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
00408 if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){
00409 LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
00410 abort();
00411 }
00412 #endif
00413 if (p==0) {
00414 LM_WARN("free(0) called\n");
00415 return;
00416 }
00417 f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
00418 #ifdef DBG_F_MALLOC
00419 LM_DBG("freeing block alloc'ed from %s: %s(%ld)\n", f->file, f->func,
00420 f->line);
00421 #endif
00422 size=f->size;
00423
00424 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00425 qm->used-=size;
00426 qm->real_used-=size;
00427 #endif
00428 #ifdef DBG_F_MALLOC
00429 f->file=file;
00430 f->func=func;
00431 f->line=line;
00432 #endif
00433 fm_insert_free(qm, f);
00434 }
00435
00436
00437 #ifdef DBG_F_MALLOC
00438 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size,
00439 const char* file, const char* func, unsigned int line)
00440 #else
00441 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
00442 #endif
00443 {
00444 struct fm_frag *f;
00445 struct fm_frag **pf;
00446 unsigned long diff;
00447 unsigned long orig_size;
00448 struct fm_frag *n;
00449 void *ptr;
00450 int hash;
00451
00452 #ifdef DBG_F_MALLOC
00453 LM_DBG("params(%p, %p, %lu), called from %s: %s(%d)\n", qm, p, size,
00454 file, func, line);
00455 if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
00456 LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
00457 abort();
00458 }
00459 #endif
00460 if (size==0) {
00461 if (p)
00462 #ifdef DBG_F_MALLOC
00463 fm_free(qm, p, file, func, line);
00464 #else
00465 fm_free(qm, p);
00466 #endif
00467 return 0;
00468 }
00469 if (p==0)
00470 #ifdef DBG_F_MALLOC
00471 return fm_malloc(qm, size, file, func, line);
00472 #else
00473 return fm_malloc(qm, size);
00474 #endif
00475 f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
00476 #ifdef DBG_F_MALLOC
00477 LM_DBG("realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
00478 f, f->file, f->func, f->line);
00479 #endif
00480 size=ROUNDUP(size);
00481 orig_size=f->size;
00482 if (f->size > size){
00483
00484 #ifdef DBG_F_MALLOC
00485 LM_DBG("shrinking from %lu to %lu\n", f->size, size);
00486 fm_split_frag(qm, f, size, file, "frag. from fm_realloc", line);
00487 #else
00488 fm_split_frag(qm, f, size);
00489 #endif
00490 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00491 qm->real_used-=(orig_size-f->size-FRAG_OVERHEAD);
00492 qm->used-=(orig_size-f->size);
00493 #endif
00494 }else if (f->size<size){
00495
00496 #ifdef DBG_F_MALLOC
00497 LM_DBG("growing from %lu to %lu\n", f->size, size);
00498 #endif
00499 diff=size-f->size;
00500 n=FRAG_NEXT(f);
00501 if (((char*)n < (char*)qm->last_frag) &&
00502 (n->u.nxt_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
00503
00504
00505 hash=GET_HASH(n->size);
00506 pf=&(qm->free_hash[hash].first);
00507
00508 for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free));
00509 if (*pf==0){
00510
00511 LM_CRIT("could not find %p in free "
00512 "list (hash=%ld)\n", n, GET_HASH(n->size));
00513 abort();
00514 }
00515
00516 *pf=n->u.nxt_free;
00517 qm->free_hash[hash].no--;
00518 #ifdef F_MALLOC_HASH_BITMAP
00519 if (qm->free_hash[hash].no==0)
00520 fm_bmp_reset(qm, hash);
00521 #endif
00522
00523 f->size+=n->size+FRAG_OVERHEAD;
00524 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00525 qm->real_used-=FRAG_OVERHEAD;
00526 #endif
00527
00528 if (f->size > size){
00529 #ifdef DBG_F_MALLOC
00530 fm_split_frag(qm, f, size, file, "fragm. from fm_realloc",
00531 line);
00532 #else
00533 fm_split_frag(qm, f, size);
00534 #endif
00535 }
00536 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00537 qm->real_used+=(f->size-orig_size);
00538 qm->used+=(f->size-orig_size);
00539 #endif
00540 }else{
00541
00542 #ifdef DBG_F_MALLOC
00543 ptr=fm_malloc(qm, size, file, func, line);
00544 #else
00545 ptr=fm_malloc(qm, size);
00546 #endif
00547 if (ptr){
00548
00549 memcpy(ptr, p, orig_size);
00550 #ifdef DBG_F_MALLOC
00551 fm_free(qm, p, file, func, line);
00552 #else
00553 fm_free(qm, p);
00554 #endif
00555 }
00556 p=ptr;
00557 }
00558 }else{
00559
00560 #ifdef DBG_F_MALLOC
00561 LM_DBG("doing nothing, same size: %lu - %lu\n", f->size, size);
00562 #endif
00563 }
00564 #ifdef DBG_F_MALLOC
00565 LM_DBG("returning %p\n", p);
00566 #endif
00567 return p;
00568 }
00569
00570
00571
00572 void fm_status(struct fm_block* qm)
00573 {
00574 struct fm_frag* f;
00575 int i,j;
00576 int h;
00577 int unused;
00578 unsigned long size;
00579
00580 LM_GEN1(memlog, "fm_status (%p):\n", qm);
00581 if (!qm) return;
00582
00583 LM_GEN1(memlog, " heap size= %ld\n", qm->size);
00584 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00585 LM_GEN1(memlog, " used= %lu, used+overhead=%lu, free=%lu\n",
00586 qm->used, qm->real_used, qm->size-qm->real_used);
00587 LM_GEN1(memlog, " max used (+overhead)= %lu\n", qm->max_real_used);
00588 #endif
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 LM_GEN1(memlog, "dumping free list:\n");
00603 for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
00604 unused=0;
00605 for (f=qm->free_hash[h].first,j=0; f;
00606 size+=f->size,f=f->u.nxt_free,i++,j++){
00607 if (!FRAG_WAS_USED(f)){
00608 unused++;
00609 #ifdef DBG_F_MALLOC
00610 LM_GEN1(memlog, "unused fragm.: hash = %3d, fragment %p,"
00611 " address %p size %lu, created from %s: %s(%ld)\n",
00612 h, f, (char*)f+sizeof(struct fm_frag), f->size,
00613 f->file, f->func, f->line);
00614 #endif
00615 };
00616 }
00617 if (j) LM_GEN1(memlog,"hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
00618 " bucket size: %9lu - %9lu (first %9lu)\n",
00619 h, j, unused, UN_HASH(h),
00620 ((h<=F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* UN_HASH(h),
00621 qm->free_hash[h].first->size
00622 );
00623 if (j!=qm->free_hash[h].no){
00624 LM_CRIT("different free frag. count: %d!=%ld"
00625 " for hash %3d\n", j, qm->free_hash[h].no, h);
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 }
00640 LM_GEN1(memlog, "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
00641 LM_GEN1(memlog, "-----------------------------\n");
00642 }
00643
00644
00645
00646
00647
00648 void fm_info(struct fm_block* qm, struct mem_info* info)
00649 {
00650 int r;
00651 long total_frags;
00652 #if !defined(DBG_F_MALLOC) && !defined(STATISTICS)
00653 struct fm_frag* f;
00654 #endif
00655
00656 memset(info,0, sizeof(*info));
00657 total_frags=0;
00658 info->total_size=qm->size;
00659 info->min_frag=MIN_FRAG_SIZE;
00660 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00661 info->free=qm->size-qm->real_used;
00662 info->used=qm->used;
00663 info->real_used=qm->real_used;
00664 info->max_used=qm->max_real_used;
00665 for(r=0;r<F_HASH_SIZE; r++){
00666 total_frags+=qm->free_hash[r].no;
00667 }
00668 #else
00669
00670 for (r=0; r<=F_MALLOC_OPTIMIZE/ROUNDTO; r++){
00671 info->free+=qm->free_hash[r].no*UN_HASH(r);
00672 total_frags+=qm->free_hash[r].no;
00673 }
00674 for(;r<F_HASH_SIZE; r++){
00675 total_frags+=qm->free_hash[r].no;
00676 for(f=qm->free_hash[r].first;f;f=f->u.nxt_free){
00677 info->free+=f->size;
00678 }
00679 }
00680 info->real_used=info->total_size-info->free;
00681 info->used=0;
00682 info->used=info->real_used-total_frags*FRAG_OVERHEAD-INIT_OVERHEAD-
00683 FRAG_OVERHEAD;
00684 info->max_used=0;
00685 #endif
00686 info->total_frags=total_frags;
00687 }
00688
00689
00690
00691
00692
00693 unsigned long fm_available(struct fm_block* qm)
00694 {
00695
00696 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00697 return qm->size-qm->real_used;
00698 #else
00699
00700
00701 return ((unsigned long)-1);
00702 #endif
00703 }
00704
00705 #endif