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
00045 #if !defined(q_malloc) && !(defined F_MALLOC)
00046 #define q_malloc
00047
00048 #include <stdlib.h>
00049 #include <string.h>
00050
00051 #include "q_malloc.h"
00052 #include "../dprint.h"
00053 #include "../globals.h"
00054 #include "memdbg.h"
00055 #include "../cfg/cfg.h"
00056 #ifdef MALLOC_STATS
00057 #include "../events.h"
00058 #endif
00059
00060
00061
00062 #define FRAG_END(f) \
00063 ((struct qm_frag_end*)((char*)(f)+sizeof(struct qm_frag)+ \
00064 (f)->size))
00065
00066 #define FRAG_NEXT(f) \
00067 ((struct qm_frag*)((char*)(f)+sizeof(struct qm_frag)+(f)->size+ \
00068 sizeof(struct qm_frag_end)))
00069
00070 #define FRAG_PREV(f) \
00071 ( (struct qm_frag*) ( ((char*)(f)-sizeof(struct qm_frag_end))- \
00072 ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))->size- \
00073 sizeof(struct qm_frag) ) )
00074
00075 #define PREV_FRAG_END(f) \
00076 ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))
00077
00078
00079 #define FRAG_OVERHEAD (sizeof(struct qm_frag)+sizeof(struct qm_frag_end))
00080
00081
00082 #define ROUNDTO_MASK (~((unsigned long)ROUNDTO-1))
00083 #define ROUNDUP(s) (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
00084 #define ROUNDDOWN(s) ((s)&ROUNDTO_MASK)
00085
00086
00087
00088
00089 #define GET_HASH(s) ( ((unsigned long)(s)<=QM_MALLOC_OPTIMIZE)?\
00090 (unsigned long)(s)/ROUNDTO: \
00091 QM_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
00092 QM_MALLOC_OPTIMIZE_FACTOR+1 )
00093
00094 #define UN_HASH(h) ( ((unsigned long)(h)<=(QM_MALLOC_OPTIMIZE/ROUNDTO))?\
00095 (unsigned long)(h)*ROUNDTO: \
00096 1UL<<((h)-QM_MALLOC_OPTIMIZE/ROUNDTO+\
00097 QM_MALLOC_OPTIMIZE_FACTOR-1)\
00098 )
00099
00100
00101
00102 #define FRAG_MARK_USED(f)
00103 #define FRAG_CLEAR_USED(f)
00104 #define FRAG_WAS_USED(f) (1)
00105
00106
00107
00108
00109
00110
00111 #define MEM_FRAG_AVOIDANCE
00112
00113
00114
00115 inline static unsigned long big_hash_idx(unsigned long s)
00116 {
00117 int idx;
00118
00119
00120
00121
00122 idx=sizeof(long)*8-1;
00123 for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
00124 return idx;
00125 }
00126
00127
00128 #ifdef DBG_QM_MALLOC
00129 #define ST_CHECK_PATTERN 0xf0f0f0f0
00130 #define END_CHECK_PATTERN1 0xc0c0c0c0
00131 #define END_CHECK_PATTERN2 0xabcdefed
00132
00133
00134 static void qm_debug_frag(struct qm_block* qm, struct qm_frag* f)
00135 {
00136 if (f->check!=ST_CHECK_PATTERN){
00137 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
00138 "beginning overwritten(%lx)!\n",
00139 f, (char*)f+sizeof(struct qm_frag),
00140 f->check);
00141 qm_status(qm);
00142 abort();
00143 };
00144 if ((FRAG_END(f)->check1!=END_CHECK_PATTERN1)||
00145 (FRAG_END(f)->check2!=END_CHECK_PATTERN2)){
00146 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p)"
00147 " end overwritten(%lx, %lx)!\n",
00148 f, (char*)f+sizeof(struct qm_frag),
00149 FRAG_END(f)->check1, FRAG_END(f)->check2);
00150 qm_status(qm);
00151 abort();
00152 }
00153 if ((f>qm->first_frag)&&
00154 ((PREV_FRAG_END(f)->check1!=END_CHECK_PATTERN1) ||
00155 (PREV_FRAG_END(f)->check2!=END_CHECK_PATTERN2) ) ){
00156 LOG(L_CRIT, "BUG: qm_*: prev. fragm. tail overwritten(%lx, %lx)[%p:%p]!"
00157 "\n",
00158 PREV_FRAG_END(f)->check1, PREV_FRAG_END(f)->check2, f,
00159 (char*)f+sizeof(struct qm_frag));
00160 qm_status(qm);
00161 abort();
00162 }
00163 }
00164 #endif
00165
00166
00167
00168 static inline void qm_insert_free(struct qm_block* qm, struct qm_frag* frag)
00169 {
00170 struct qm_frag* f;
00171 struct qm_frag* prev;
00172 int hash;
00173
00174 hash=GET_HASH(frag->size);
00175 for(f=qm->free_hash[hash].head.u.nxt_free; f!=&(qm->free_hash[hash].head);
00176 f=f->u.nxt_free){
00177 if (frag->size <= f->size) break;
00178 }
00179
00180 prev=FRAG_END(f)->prev_free;
00181 prev->u.nxt_free=frag;
00182 FRAG_END(frag)->prev_free=prev;
00183 frag->u.nxt_free=f;
00184 FRAG_END(f)->prev_free=frag;
00185 qm->free_hash[hash].no++;
00186 }
00187
00188
00189
00190
00191 struct qm_block* qm_malloc_init(char* address, unsigned long size)
00192 {
00193 char* start;
00194 char* end;
00195 struct qm_block* qm;
00196 unsigned long init_overhead;
00197 int h;
00198
00199
00200 start=(char*)ROUNDUP((unsigned long) address);
00201 DBG("qm_malloc_init: QM_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
00202 QM_MALLOC_OPTIMIZE, QM_MALLOC_OPTIMIZE/ROUNDTO);
00203 DBG("qm_malloc_init: QM_HASH_SIZE=%lu, qm_block size=%lu\n",
00204 QM_HASH_SIZE, (long)sizeof(struct qm_block));
00205 DBG("qm_malloc_init(%p, %lu), start=%p\n", address, size, start);
00206 if (size<start-address) return 0;
00207 size-=(start-address);
00208 if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
00209 size=ROUNDDOWN(size);
00210
00211 init_overhead=ROUNDUP(sizeof(struct qm_block))+sizeof(struct qm_frag)+
00212 sizeof(struct qm_frag_end);
00213 DBG("qm_malloc_init: size= %lu, init_overhead=%lu\n", size, init_overhead);
00214
00215 if (size < init_overhead)
00216 {
00217
00218 return 0;
00219 }
00220 end=start+size;
00221 qm=(struct qm_block*)start;
00222 memset(qm, 0, sizeof(struct qm_block));
00223 qm->size=size;
00224 qm->real_used=init_overhead;
00225 qm->max_real_used=qm->real_used;
00226 size-=init_overhead;
00227
00228 qm->first_frag=(struct qm_frag*)(start+ROUNDUP(sizeof(struct qm_block)));
00229 qm->last_frag_end=(struct qm_frag_end*)(end-sizeof(struct qm_frag_end));
00230
00231 qm->first_frag->size=size;
00232 qm->last_frag_end->size=size;
00233
00234 #ifdef DBG_QM_MALLOC
00235 qm->first_frag->check=ST_CHECK_PATTERN;
00236 qm->last_frag_end->check1=END_CHECK_PATTERN1;
00237 qm->last_frag_end->check2=END_CHECK_PATTERN2;
00238 #endif
00239
00240 for (h=0; h<QM_HASH_SIZE;h++){
00241 qm->free_hash[h].head.u.nxt_free=&(qm->free_hash[h].head);
00242 qm->free_hash[h].tail.prev_free=&(qm->free_hash[h].head);
00243 qm->free_hash[h].head.size=0;
00244 qm->free_hash[h].tail.size=0;
00245 }
00246
00247
00248
00249 qm_insert_free(qm, qm->first_frag);
00250
00251
00252
00253
00254
00255
00256 return qm;
00257 }
00258
00259
00260
00261 static inline void qm_detach_free(struct qm_block* qm, struct qm_frag* frag)
00262 {
00263 struct qm_frag *prev;
00264 struct qm_frag *next;
00265
00266 prev=FRAG_END(frag)->prev_free;
00267 next=frag->u.nxt_free;
00268 prev->u.nxt_free=next;
00269 FRAG_END(next)->prev_free=prev;
00270
00271 }
00272
00273
00274
00275 #ifdef DBG_QM_MALLOC
00276 static inline struct qm_frag* qm_find_free(struct qm_block* qm,
00277 unsigned long size,
00278 int *h,
00279 unsigned int *count)
00280 #else
00281 static inline struct qm_frag* qm_find_free(struct qm_block* qm,
00282 unsigned long size,
00283 int* h)
00284 #endif
00285 {
00286 int hash;
00287 struct qm_frag* f;
00288
00289 for (hash=GET_HASH(size); hash<QM_HASH_SIZE; hash++){
00290 for (f=qm->free_hash[hash].head.u.nxt_free;
00291 f!=&(qm->free_hash[hash].head); f=f->u.nxt_free){
00292 #ifdef DBG_QM_MALLOC
00293 *count+=1;
00294 #endif
00295 if (f->size>=size){ *h=hash; return f; }
00296 }
00297
00298 }
00299
00300 return 0;
00301 }
00302
00303
00304
00305
00306 static inline
00307 #ifdef DBG_QM_MALLOC
00308 int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size,
00309 const char* file, const char* func, unsigned int line)
00310 #else
00311 int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size)
00312 #endif
00313 {
00314 unsigned long rest;
00315 struct qm_frag* n;
00316 struct qm_frag_end* end;
00317
00318 rest=f->size-new_size;
00319 #ifdef MEM_FRAG_AVOIDANCE
00320 if ((rest> (FRAG_OVERHEAD+QM_MALLOC_OPTIMIZE))||
00321 (rest>=(FRAG_OVERHEAD+new_size))){
00322 #else
00323 if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
00324 #endif
00325 f->size=new_size;
00326
00327 end=FRAG_END(f);
00328 end->size=new_size;
00329 n=(struct qm_frag*)((char*)end+sizeof(struct qm_frag_end));
00330 n->size=rest-FRAG_OVERHEAD;
00331 FRAG_END(n)->size=n->size;
00332 FRAG_CLEAR_USED(n);
00333 qm->real_used+=FRAG_OVERHEAD;
00334 #ifdef DBG_QM_MALLOC
00335 end->check1=END_CHECK_PATTERN1;
00336 end->check2=END_CHECK_PATTERN2;
00337
00338 n->file=file;
00339 n->func=func;
00340 n->line=line;
00341 n->check=ST_CHECK_PATTERN;
00342 #endif
00343
00344 qm_insert_free(qm, n);
00345 return 0;
00346 }else{
00347
00348 return -1;
00349 }
00350 }
00351
00352
00353
00354 #ifdef DBG_QM_MALLOC
00355 void* qm_malloc(struct qm_block* qm, unsigned long size,
00356 const char* file, const char* func, unsigned int line)
00357 #else
00358 void* qm_malloc(struct qm_block* qm, unsigned long size)
00359 #endif
00360 {
00361 struct qm_frag* f;
00362 int hash;
00363
00364 #ifdef DBG_QM_MALLOC
00365 unsigned int list_cntr;
00366
00367 list_cntr = 0;
00368 MDBG("qm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
00369 line);
00370 #endif
00371
00372 size=ROUNDUP(size);
00373 if (size>(qm->size-qm->real_used)) return 0;
00374
00375
00376 #ifdef DBG_QM_MALLOC
00377 if ((f=qm_find_free(qm, size, &hash, &list_cntr))!=0){
00378 #else
00379 if ((f=qm_find_free(qm, size, &hash))!=0){
00380 #endif
00381
00382
00383 #ifdef DBG_QM_MALLOC
00384 qm_debug_frag(qm, f);
00385 #endif
00386 qm_detach_free(qm, f);
00387
00388 f->u.is_free=0;
00389 qm->free_hash[hash].no--;
00390
00391 #ifdef DBG_QM_MALLOC
00392 split_frag(qm, f, size, file, "fragm. from qm_malloc", line);
00393 #else
00394 split_frag(qm, f, size);
00395 #endif
00396 qm->real_used+=f->size;
00397 qm->used+=f->size;
00398 if (qm->max_real_used<qm->real_used)
00399 qm->max_real_used=qm->real_used;
00400 #ifdef MALLOC_STATS
00401 sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00402 sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00403 #endif
00404 #ifdef DBG_QM_MALLOC
00405 f->file=file;
00406 f->func=func;
00407 f->line=line;
00408 f->check=ST_CHECK_PATTERN;
00409
00410
00411 MDBG("qm_malloc(%p, %lu) returns address %p frag. %p (size=%lu) on %d"
00412 " -th hit\n",
00413 qm, size, (char*)f+sizeof(struct qm_frag), f, f->size, list_cntr );
00414 #endif
00415 return (char*)f+sizeof(struct qm_frag);
00416 }
00417 return 0;
00418 }
00419
00420
00421
00422 #ifdef DBG_QM_MALLOC
00423 void qm_free(struct qm_block* qm, void* p, const char* file, const char* func,
00424 unsigned int line)
00425 #else
00426 void qm_free(struct qm_block* qm, void* p)
00427 #endif
00428 {
00429 struct qm_frag* f;
00430 unsigned long size;
00431 #ifdef MEM_JOIN_FREE
00432 struct qm_frag* next;
00433 struct qm_frag* prev;
00434 #endif
00435
00436 #ifdef DBG_QM_MALLOC
00437 MDBG("qm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
00438 if (p>(void*)qm->last_frag_end || p<(void*)qm->first_frag){
00439 LOG(L_CRIT, "BUG: qm_free: bad pointer %p (out of memory block!)"
00440 " called from %s: %s(%d) - aborting\n", p, file, func, line);
00441 if(likely(cfg_get(core, core_cfg, mem_safety)==0))
00442 abort();
00443 }
00444 #endif
00445 if (p==0) {
00446 LOG(L_WARN, "WARNING:qm_free: free(0) called\n");
00447 return;
00448 }
00449 f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
00450 #ifdef DBG_QM_MALLOC
00451 qm_debug_frag(qm, f);
00452 if (f->u.is_free){
00453 LOG(L_CRIT, "BUG: qm_free: freeing already freed pointer (%p),"
00454 " called from %s: %s(%d), first free %s: %s(%ld) - aborting\n",
00455 p, file, func, line, f->file, f->func, f->line);
00456 if(likely(cfg_get(core, core_cfg, mem_safety)==0))
00457 abort();
00458 }
00459 MDBG("qm_free: freeing frag. %p alloc'ed from %s: %s(%ld)\n",
00460 f, f->file, f->func, f->line);
00461 #endif
00462 size=f->size;
00463 qm->used-=size;
00464 qm->real_used-=size;
00465 #ifdef MALLOC_STATS
00466 sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00467 sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00468 #endif
00469
00470 #ifdef MEM_JOIN_FREE
00471 if(unlikely(cfg_get(core, core_cfg, mem_join)!=0)) {
00472 next=prev=0;
00473
00474
00475
00476 f->u.nxt_free=(void*)0x1L;
00477
00478 next=FRAG_NEXT(f);
00479 if (((char*)next < (char*)qm->last_frag_end) &&( next->u.is_free)){
00480
00481 #ifdef DBG_QM_MALLOC
00482 qm_debug_frag(qm, next);
00483 #endif
00484 qm_detach_free(qm, next);
00485 size+=next->size+FRAG_OVERHEAD;
00486 qm->real_used-=FRAG_OVERHEAD;
00487 qm->free_hash[GET_HASH(next->size)].no--;
00488 }
00489
00490 if (f > qm->first_frag){
00491 prev=FRAG_PREV(f);
00492
00493
00494 #ifdef DBG_QM_MALLOC
00495 qm_debug_frag(qm, prev);
00496 #endif
00497 if (prev->u.is_free){
00498
00499 qm_detach_free(qm, prev);
00500 size+=prev->size+FRAG_OVERHEAD;
00501 qm->real_used-=FRAG_OVERHEAD;
00502 qm->free_hash[GET_HASH(prev->size)].no--;
00503 f=prev;
00504 }
00505 }
00506 f->size=size;
00507 FRAG_END(f)->size=f->size;
00508 }
00509 #endif
00510 #ifdef DBG_QM_MALLOC
00511 f->file=file;
00512 f->func=func;
00513 f->line=line;
00514 #endif
00515 qm_insert_free(qm, f);
00516 }
00517
00518
00519
00520 #ifdef DBG_QM_MALLOC
00521 void* qm_realloc(struct qm_block* qm, void* p, unsigned long size,
00522 const char* file, const char* func, unsigned int line)
00523 #else
00524 void* qm_realloc(struct qm_block* qm, void* p, unsigned long size)
00525 #endif
00526 {
00527 struct qm_frag* f;
00528 unsigned long diff;
00529 unsigned long orig_size;
00530 struct qm_frag* n;
00531 void* ptr;
00532
00533
00534 #ifdef DBG_QM_MALLOC
00535 MDBG("qm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p, size,
00536 file, func, line);
00537 if ((p)&&(p>(void*)qm->last_frag_end || p<(void*)qm->first_frag)){
00538 LOG(L_CRIT, "BUG: qm_free: bad pointer %p (out of memory block!) - "
00539 "aborting\n", p);
00540 abort();
00541 }
00542 #endif
00543
00544 if (size==0) {
00545 if (p)
00546 #ifdef DBG_QM_MALLOC
00547 qm_free(qm, p, file, func, line);
00548 #else
00549 qm_free(qm, p);
00550 #endif
00551 return 0;
00552 }
00553 if (p==0)
00554 #ifdef DBG_QM_MALLOC
00555 return qm_malloc(qm, size, file, func, line);
00556 #else
00557 return qm_malloc(qm, size);
00558 #endif
00559 f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
00560 #ifdef DBG_QM_MALLOC
00561 qm_debug_frag(qm, f);
00562 MDBG("qm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
00563 f, f->file, f->func, f->line);
00564 if (f->u.is_free){
00565 LOG(L_CRIT, "BUG:qm_realloc: trying to realloc an already freed "
00566 "pointer %p , fragment %p -- aborting\n", p, f);
00567 abort();
00568 }
00569 #endif
00570
00571 size=ROUNDUP(size);
00572 if (f->size > size){
00573 orig_size=f->size;
00574
00575 #ifdef DBG_QM_MALLOC
00576 MDBG("qm_realloc: shrinking from %lu to %lu\n", f->size, size);
00577 if(split_frag(qm, f, size, file, "fragm. from qm_realloc", line)!=0){
00578 MDBG("qm_realloc : shrinked successful\n");
00579 #else
00580 if(split_frag(qm, f, size)!=0){
00581 #endif
00582
00583
00584
00585
00586 qm->real_used-=(orig_size-f->size);
00587 qm->used-=(orig_size-f->size);
00588 #ifdef MALLOC_STATS
00589 sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00590 sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00591 #endif
00592 }
00593
00594 }else if (f->size < size){
00595
00596 #ifdef DBG_QM_MALLOC
00597 MDBG("qm_realloc: growing from %lu to %lu\n", f->size, size);
00598 #endif
00599 orig_size=f->size;
00600 diff=size-f->size;
00601 n=FRAG_NEXT(f);
00602 if (((char*)n < (char*)qm->last_frag_end) &&
00603 (n->u.is_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
00604
00605 qm_detach_free(qm, n);
00606 qm->free_hash[GET_HASH(n->size)].no--;
00607 f->size+=n->size+FRAG_OVERHEAD;
00608 qm->real_used-=FRAG_OVERHEAD;
00609 FRAG_END(f)->size=f->size;
00610
00611
00612 if (f->size > size ){
00613 #ifdef DBG_QM_MALLOC
00614 split_frag(qm, f, size, file, "fragm. from qm_realloc",
00615 line);
00616 #else
00617 split_frag(qm, f, size);
00618 #endif
00619 }
00620 qm->real_used+=(f->size-orig_size);
00621 qm->used+=(f->size-orig_size);
00622 #ifdef MALLOC_STATS
00623 sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00624 sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00625 #endif
00626 }else{
00627
00628 #ifdef DBG_QM_MALLOC
00629 ptr=qm_malloc(qm, size, file, func, line);
00630 #else
00631 ptr=qm_malloc(qm, size);
00632 #endif
00633 if (ptr){
00634
00635 memcpy(ptr, p, orig_size);
00636 #ifdef DBG_QM_MALLOC
00637 qm_free(qm, p, file, func, line);
00638 #else
00639 qm_free(qm, p);
00640 #endif
00641 }
00642 p=ptr;
00643 }
00644 }else{
00645
00646 #ifdef DBG_QM_MALLOC
00647 MDBG("qm_realloc: doing nothing, same size: %lu - %lu\n",
00648 f->size, size);
00649 #endif
00650 }
00651 #ifdef DBG_QM_MALLOC
00652 MDBG("qm_realloc: returning %p\n", p);
00653 #endif
00654 return p;
00655 }
00656
00657
00658 void qm_check(struct qm_block* qm)
00659 {
00660 struct qm_frag* f;
00661 long fcount = 0;
00662 int memlog;
00663
00664 memlog=cfg_get(core, core_cfg, memlog);
00665 LOG(memlog, "DEBUG: qm_check()\n");
00666 f = qm->first_frag;
00667 while ((char*)f < (char*)qm->last_frag_end) {
00668 fcount++;
00669
00670 #ifdef DBG_QM_MALLOC
00671 if (f->check!=ST_CHECK_PATTERN){
00672 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
00673 "beginning overwritten(%lx)!\n",
00674 f, (char*)f + sizeof(struct qm_frag),
00675 f->check);
00676 qm_status(qm);
00677 abort();
00678 };
00679 #endif
00680 if (f + sizeof(struct qm_frag) + f->size + sizeof(struct qm_frag_end) > qm->first_frag + qm->size) {
00681 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
00682 "bad size: %lu (frag end: %p > end of block: %p)\n",
00683 f, (char*)f + sizeof(struct qm_frag) + sizeof(struct qm_frag_end), f->size,
00684 f + sizeof(struct qm_frag) + f->size, qm->first_frag + qm->size);
00685 qm_status(qm);
00686 abort();
00687 }
00688
00689 if (FRAG_END(f)->size != f->size) {
00690 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
00691 "size in qm_frag and qm_frag_end does not match: frag->size=%lu, frag_end->size=%lu)\n",
00692 f, (char*)f + sizeof(struct qm_frag),
00693 f->size, FRAG_END(f)->size);
00694 qm_status(qm);
00695 abort();
00696 }
00697 #ifdef DBG_QM_MALLOC
00698 if ((FRAG_END(f)->check1 != END_CHECK_PATTERN1) ||
00699 (FRAG_END(f)->check2 != END_CHECK_PATTERN2)) {
00700 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p)"
00701 " end overwritten(%lx, %lx)!\n",
00702 f, (char*)f + sizeof(struct qm_frag),
00703 FRAG_END(f)->check1, FRAG_END(f)->check2);
00704 qm_status(qm);
00705 abort();
00706 }
00707 #endif
00708 f = FRAG_NEXT(f);
00709 }
00710
00711 LOG(memlog, "DEBUG: qm_check: %lu fragments OK\n", fcount);
00712 }
00713
00714 void qm_status(struct qm_block* qm)
00715 {
00716 struct qm_frag* f;
00717 int i,j;
00718 int h;
00719 int unused;
00720 int memlog;
00721 int mem_summary;
00722
00723 memlog=cfg_get(core, core_cfg, memlog);
00724 mem_summary=cfg_get(core, core_cfg, mem_summary);
00725 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ", "(%p):\n", qm);
00726 if (!qm) return;
00727
00728 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ", "heap size= %lu\n",
00729 qm->size);
00730 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00731 "used= %lu, used+overhead=%lu, free=%lu\n",
00732 qm->used, qm->real_used, qm->size-qm->real_used);
00733 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00734 "max used (+overhead)= %lu\n", qm->max_real_used);
00735
00736 if (mem_summary & 16) return;
00737
00738 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00739 "dumping all alloc'ed. fragments:\n");
00740 for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;f=FRAG_NEXT(f)
00741 ,i++){
00742 if (! f->u.is_free){
00743 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00744 " %3d. %c address=%p frag=%p size=%lu used=%d\n",
00745 i,
00746 (f->u.is_free)?'a':'N',
00747 (char*)f+sizeof(struct qm_frag), f, f->size, FRAG_WAS_USED(f));
00748 #ifdef DBG_QM_MALLOC
00749 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00750 " %s from %s: %s(%ld)\n",
00751 (f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
00752 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00753 " start check=%lx, end check= %lx, %lx\n",
00754 f->check, FRAG_END(f)->check1, FRAG_END(f)->check2);
00755 #endif
00756 }
00757 }
00758 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00759 "dumping free list stats :\n");
00760 for(h=0,i=0;h<QM_HASH_SIZE;h++){
00761 unused=0;
00762 for (f=qm->free_hash[h].head.u.nxt_free,j=0;
00763 f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++){
00764 if (!FRAG_WAS_USED(f)){
00765 unused++;
00766 #ifdef DBG_QM_MALLOC
00767 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00768 "unused fragm.: hash = %3d, fragment %p,"
00769 " address %p size %lu, created from %s: %s(%lu)\n",
00770 h, f, (char*)f+sizeof(struct qm_frag), f->size,
00771 f->file, f->func, f->line);
00772 #endif
00773 }
00774 }
00775
00776 if (j) LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00777 "hash= %3d. fragments no.: %5d, unused: %5d\n"
00778 "\t\t bucket size: %9lu - %9ld (first %9lu)\n",
00779 h, j, unused, UN_HASH(h),
00780 ((h<=QM_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
00781 qm->free_hash[h].head.u.nxt_free->size
00782 );
00783 if (j!=qm->free_hash[h].no){
00784 LOG(L_CRIT, "BUG: qm_status: different free frag. count: %d!=%lu"
00785 " for hash %3d\n", j, qm->free_hash[h].no, h);
00786 }
00787
00788 }
00789 LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
00790 "-----------------------------\n");
00791 }
00792
00793
00794
00795
00796 void qm_info(struct qm_block* qm, struct mem_info* info)
00797 {
00798 int r;
00799 long total_frags;
00800
00801 total_frags=0;
00802 memset(info,0, sizeof(*info));
00803 info->total_size=qm->size;
00804 info->min_frag=MIN_FRAG_SIZE;
00805 info->free=qm->size-qm->real_used;
00806 info->used=qm->used;
00807 info->real_used=qm->real_used;
00808 info->max_used=qm->max_real_used;
00809 for(r=0;r<QM_HASH_SIZE; r++){
00810 total_frags+=qm->free_hash[r].no;
00811 }
00812 info->total_frags=total_frags;
00813 }
00814
00815
00816
00817
00818 unsigned long qm_available(struct qm_block* qm)
00819 {
00820 return qm->size-qm->real_used;
00821 }
00822
00823
00824
00825 #ifdef DBG_QM_MALLOC
00826
00827 typedef struct _mem_counter{
00828 const char *file;
00829 const char *func;
00830 unsigned long line;
00831
00832 unsigned long size;
00833 int count;
00834
00835 struct _mem_counter *next;
00836 } mem_counter;
00837
00838 static mem_counter* get_mem_counter(mem_counter **root, struct qm_frag* f)
00839 {
00840 mem_counter *x;
00841 if (!*root) goto make_new;
00842 for(x=*root;x;x=x->next)
00843 if (x->file == f->file && x->func == f->func && x->line == f->line)
00844 return x;
00845 make_new:
00846 x = malloc(sizeof(mem_counter));
00847 x->file = f->file;
00848 x->func = f->func;
00849 x->line = f->line;
00850 x->count = 0;
00851 x->size = 0;
00852 x->next = *root;
00853 *root = x;
00854 return x;
00855 }
00856
00857
00858
00859 void qm_sums(struct qm_block* qm)
00860 {
00861 struct qm_frag* f;
00862 int i;
00863 mem_counter *root, *x;
00864 int memlog;
00865
00866 root=0;
00867 if (!qm) return;
00868
00869 memlog=cfg_get(core, core_cfg, memlog);
00870 LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
00871 "summarizing all alloc'ed. fragments:\n");
00872
00873 for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;
00874 f=FRAG_NEXT(f),i++){
00875 if (! f->u.is_free){
00876 x = get_mem_counter(&root,f);
00877 x->count++;
00878 x->size+=f->size;
00879 }
00880 }
00881 x = root;
00882 while(x){
00883 LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
00884 " count=%6d size=%10lu bytes from %s: %s(%ld)\n",
00885 x->count,x->size,
00886 x->file, x->func, x->line
00887 );
00888 root = x->next;
00889 free(x);
00890 x = root;
00891 }
00892 LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
00893 "-----------------------------\n");
00894 }
00895 #endif
00896
00897
00898 #endif