09cb5c735b333fa98576d1ebfee3fc756635025e
[sip-router] / mem / q_malloc.c
1 /* $Id$
2  *
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of sip-router, a free SIP server.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 /*
21  * History:
22  * --------
23  *  ????-??-??  created by andrei
24  *  2003-04-14  more debugging added in DBG_QM_MALLOC mode (andrei)
25  *  2003-06-29  added qm_realloc (andrei)
26  *  2004-07-19  fragments book keeping code and support for 64 bits
27  *               memory blocks (64 bits machine & size>=2^32) (andrei)
28  *              GET_HASH s/</<=/ (avoids waste of 1 hash cell) (andrei)
29  *  2004-11-10  support for > 4Gb mem., switched to long (andrei)
30  *  2005-03-02  added qm_info() (andrei)
31  *  2005-12-12  fixed realloc shrink real_used & used accounting;
32  *              fixed initial size (andrei)
33  *  2006-02-03  fixed realloc out of mem. free bug (andrei)
34  *  2006-04-07  s/DBG/MDBG (andrei)
35  *  2007-02-23  added fm_available() (andrei)
36  *  2009-09-28  added fm_sums() (patch from Dragos Vingarzan)
37  */
38
39
40 #if !defined(q_malloc) && !(defined F_MALLOC)
41 #define q_malloc
42
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "q_malloc.h"
47 #include "../dprint.h"
48 #include "../globals.h"
49 #include "memdbg.h"
50 #include "../cfg/cfg.h" /* memlog */
51
52
53 /*useful macros*/
54 #define FRAG_END(f)  \
55         ((struct qm_frag_end*)((char*)(f)+sizeof(struct qm_frag)+ \
56            (f)->size))
57
58 #define FRAG_NEXT(f) \
59         ((struct qm_frag*)((char*)(f)+sizeof(struct qm_frag)+(f)->size+ \
60            sizeof(struct qm_frag_end)))
61                         
62 #define FRAG_PREV(f) \
63         ( (struct qm_frag*) ( ((char*)(f)-sizeof(struct qm_frag_end))- \
64         ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))->size- \
65            sizeof(struct qm_frag) ) )
66
67 #define PREV_FRAG_END(f) \
68         ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))
69
70
71 #define FRAG_OVERHEAD   (sizeof(struct qm_frag)+sizeof(struct qm_frag_end))
72
73
74 #define ROUNDTO_MASK    (~((unsigned long)ROUNDTO-1))
75 #define ROUNDUP(s)              (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
76 #define ROUNDDOWN(s)    ((s)&ROUNDTO_MASK)
77
78 /*
79 #define ROUNDUP(s)              (((s)%ROUNDTO)?((s)+ROUNDTO)/ROUNDTO*ROUNDTO:(s))
80 #define ROUNDDOWN(s)    (((s)%ROUNDTO)?((s)-ROUNDTO)/ROUNDTO*ROUNDTO:(s))
81 */
82
83
84
85         /* finds the hash value for s, s=ROUNDTO multiple*/
86 #define GET_HASH(s)   ( ((unsigned long)(s)<=QM_MALLOC_OPTIMIZE)?\
87                                                         (unsigned long)(s)/ROUNDTO: \
88                                                         QM_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
89                                                                 QM_MALLOC_OPTIMIZE_FACTOR+1 )
90
91 #define UN_HASH(h)      ( ((unsigned long)(h)<=(QM_MALLOC_OPTIMIZE/ROUNDTO))?\
92                                                         (unsigned long)(h)*ROUNDTO: \
93                                                         1UL<<((h)-QM_MALLOC_OPTIMIZE/ROUNDTO+\
94                                                                 QM_MALLOC_OPTIMIZE_FACTOR-1)\
95                                         )
96
97
98 /* mark/test used/unused frags */
99 #define FRAG_MARK_USED(f)
100 #define FRAG_CLEAR_USED(f)
101 #define FRAG_WAS_USED(f)   (1)
102
103 /* other frag related defines:
104  * MEM_COALESCE_FRAGS 
105  * MEM_FRAG_AVOIDANCE
106  */
107
108 #define MEM_FRAG_AVOIDANCE
109
110
111 /* computes hash number for big buckets*/
112 inline static unsigned long big_hash_idx(unsigned long s)
113 {
114         int idx;
115         /* s is rounded => s = k*2^n (ROUNDTO=2^n) 
116          * index= i such that 2^i > s >= 2^(i-1)
117          *
118          * => index = number of the first non null bit in s*/
119         idx=sizeof(long)*8-1;
120         for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
121         return idx;
122 }
123
124
125 #ifdef DBG_QM_MALLOC
126 #define ST_CHECK_PATTERN   0xf0f0f0f0
127 #define END_CHECK_PATTERN1 0xc0c0c0c0
128 #define END_CHECK_PATTERN2 0xabcdefed
129
130
131 static  void qm_debug_frag(struct qm_block* qm, struct qm_frag* f)
132 {
133         if (f->check!=ST_CHECK_PATTERN){
134                 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
135                                 "beginning overwritten(%lx)!\n",
136                                 f, (char*)f+sizeof(struct qm_frag),
137                                 f->check);
138                 qm_status(qm);
139                 abort();
140         };
141         if ((FRAG_END(f)->check1!=END_CHECK_PATTERN1)||
142                 (FRAG_END(f)->check2!=END_CHECK_PATTERN2)){
143                 LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p)"
144                                         " end overwritten(%lx, %lx)!\n",
145                                 f, (char*)f+sizeof(struct qm_frag), 
146                                 FRAG_END(f)->check1, FRAG_END(f)->check2);
147                 qm_status(qm);
148                 abort();
149         }
150         if ((f>qm->first_frag)&&
151                         ((PREV_FRAG_END(f)->check1!=END_CHECK_PATTERN1) ||
152                                 (PREV_FRAG_END(f)->check2!=END_CHECK_PATTERN2) ) ){
153                 LOG(L_CRIT, "BUG: qm_*: prev. fragm. tail overwritten(%lx, %lx)[%p:%p]!"
154                                         "\n",
155                                 PREV_FRAG_END(f)->check1, PREV_FRAG_END(f)->check2, f,
156                                 (char*)f+sizeof(struct qm_frag));
157                 qm_status(qm);
158                 abort();
159         }
160 }
161 #endif
162
163
164
165 static inline void qm_insert_free(struct qm_block* qm, struct qm_frag* frag)
166 {
167         struct qm_frag* f;
168         struct qm_frag* prev;
169         int hash;
170         
171         hash=GET_HASH(frag->size);
172         for(f=qm->free_hash[hash].head.u.nxt_free; f!=&(qm->free_hash[hash].head);
173                         f=f->u.nxt_free){
174                 if (frag->size <= f->size) break;
175         }
176         /*insert it here*/
177         prev=FRAG_END(f)->prev_free;
178         prev->u.nxt_free=frag;
179         FRAG_END(frag)->prev_free=prev;
180         frag->u.nxt_free=f;
181         FRAG_END(f)->prev_free=frag;
182         qm->free_hash[hash].no++;
183 }
184
185
186
187 /* init malloc and return a qm_block*/
188 struct qm_block* qm_malloc_init(char* address, unsigned long size)
189 {
190         char* start;
191         char* end;
192         struct qm_block* qm;
193         unsigned long init_overhead;
194         int h;
195         
196         /* make address and size multiple of 8*/
197         start=(char*)ROUNDUP((unsigned long) address);
198         DBG("qm_malloc_init: QM_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
199                         QM_MALLOC_OPTIMIZE, QM_MALLOC_OPTIMIZE/ROUNDTO);
200         DBG("qm_malloc_init: QM_HASH_SIZE=%lu, qm_block size=%lu\n",
201                         QM_HASH_SIZE, (long)sizeof(struct qm_block));
202         DBG("qm_malloc_init(%p, %lu), start=%p\n", address, size, start);
203         if (size<start-address) return 0;
204         size-=(start-address);
205         if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
206         size=ROUNDDOWN(size);
207         
208         init_overhead=ROUNDUP(sizeof(struct qm_block))+sizeof(struct qm_frag)+
209                 sizeof(struct qm_frag_end);
210         DBG("qm_malloc_init: size= %lu, init_overhead=%lu\n", size, init_overhead);
211         
212         if (size < init_overhead)
213         {
214                 /* not enough mem to create our control structures !!!*/
215                 return 0;
216         }
217         end=start+size;
218         qm=(struct qm_block*)start;
219         memset(qm, 0, sizeof(struct qm_block));
220         qm->size=size;
221         qm->real_used=init_overhead;
222         qm->max_real_used=qm->real_used;
223         size-=init_overhead;
224         
225         qm->first_frag=(struct qm_frag*)(start+ROUNDUP(sizeof(struct qm_block)));
226         qm->last_frag_end=(struct qm_frag_end*)(end-sizeof(struct qm_frag_end));
227         /* init initial fragment*/
228         qm->first_frag->size=size;
229         qm->last_frag_end->size=size;
230         
231 #ifdef DBG_QM_MALLOC
232         qm->first_frag->check=ST_CHECK_PATTERN;
233         qm->last_frag_end->check1=END_CHECK_PATTERN1;
234         qm->last_frag_end->check2=END_CHECK_PATTERN2;
235 #endif
236         /* init free_hash* */
237         for (h=0; h<QM_HASH_SIZE;h++){
238                 qm->free_hash[h].head.u.nxt_free=&(qm->free_hash[h].head);
239                 qm->free_hash[h].tail.prev_free=&(qm->free_hash[h].head);
240                 qm->free_hash[h].head.size=0;
241                 qm->free_hash[h].tail.size=0;
242         }
243         
244         /* link initial fragment into the free list*/
245         
246         qm_insert_free(qm, qm->first_frag);
247         
248         /*qm->first_frag->u.nxt_free=&(qm->free_lst);
249           qm->last_frag_end->prev_free=&(qm->free_lst);
250         */
251         
252         
253         return qm;
254 }
255
256
257
258 static inline void qm_detach_free(struct qm_block* qm, struct qm_frag* frag)
259 {
260         struct qm_frag *prev;
261         struct qm_frag *next;
262         
263         prev=FRAG_END(frag)->prev_free;
264         next=frag->u.nxt_free;
265         prev->u.nxt_free=next;
266         FRAG_END(next)->prev_free=prev;
267         
268 }
269
270
271
272 #ifdef DBG_QM_MALLOC
273 static inline struct qm_frag* qm_find_free(struct qm_block* qm, 
274                                                                                         unsigned long size,
275                                                                                         int *h,
276                                                                                         unsigned int *count)
277 #else
278 static inline struct qm_frag* qm_find_free(struct qm_block* qm, 
279                                                                                         unsigned long size,
280                                                                                         int* h)
281 #endif
282 {
283         int hash;
284         struct qm_frag* f;
285
286         for (hash=GET_HASH(size); hash<QM_HASH_SIZE; hash++){
287                 for (f=qm->free_hash[hash].head.u.nxt_free; 
288                                         f!=&(qm->free_hash[hash].head); f=f->u.nxt_free){
289 #ifdef DBG_QM_MALLOC
290                         *count+=1; /* *count++ generates a warning with gcc 2.9* -Wall */
291 #endif
292                         if (f->size>=size){ *h=hash; return f; }
293                 }
294         /*try in a bigger bucket*/
295         }
296         /* not found */
297         return 0;
298 }
299
300
301 /* returns 0 on success, -1 on error;
302  * new_size < size & rounded-up already!*/
303 static inline
304 #ifdef DBG_QM_MALLOC
305 int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size,
306                                 const char* file, const char* func, unsigned int line)
307 #else
308 int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size)
309 #endif
310 {
311         unsigned long rest;
312         struct qm_frag* n;
313         struct qm_frag_end* end;
314         
315         rest=f->size-new_size;
316 #ifdef MEM_FRAG_AVOIDANCE
317         if ((rest> (FRAG_OVERHEAD+QM_MALLOC_OPTIMIZE))||
318                 (rest>=(FRAG_OVERHEAD+new_size))){/* the residue fragm. is big enough*/
319 #else
320         if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
321 #endif
322                 f->size=new_size;
323                 /*split the fragment*/
324                 end=FRAG_END(f);
325                 end->size=new_size;
326                 n=(struct qm_frag*)((char*)end+sizeof(struct qm_frag_end));
327                 n->size=rest-FRAG_OVERHEAD;
328                 FRAG_END(n)->size=n->size;
329                 FRAG_CLEAR_USED(n); /* never used */
330                 qm->real_used+=FRAG_OVERHEAD;
331 #ifdef DBG_QM_MALLOC
332                 end->check1=END_CHECK_PATTERN1;
333                 end->check2=END_CHECK_PATTERN2;
334                 /* frag created by malloc, mark it*/
335                 n->file=file;
336                 n->func=func;
337                 n->line=line;
338                 n->check=ST_CHECK_PATTERN;
339 #endif
340                 /* reinsert n in free list*/
341                 qm_insert_free(qm, n);
342                 return 0;
343         }else{
344                         /* we cannot split this fragment any more */
345                 return -1;
346         }
347 }
348
349
350
351 #ifdef DBG_QM_MALLOC
352 void* qm_malloc(struct qm_block* qm, unsigned long size,
353                                         const char* file, const char* func, unsigned int line)
354 #else
355 void* qm_malloc(struct qm_block* qm, unsigned long size)
356 #endif
357 {
358         struct qm_frag* f;
359         int hash;
360         
361 #ifdef DBG_QM_MALLOC
362         unsigned int list_cntr;
363
364         list_cntr = 0;
365         MDBG("qm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
366                         line);
367 #endif
368         /*size must be a multiple of 8*/
369         size=ROUNDUP(size);
370         if (size>(qm->size-qm->real_used)) return 0;
371
372         /*search for a suitable free frag*/
373 #ifdef DBG_QM_MALLOC
374         if ((f=qm_find_free(qm, size, &hash, &list_cntr))!=0){
375 #else
376         if ((f=qm_find_free(qm, size, &hash))!=0){
377 #endif
378                 /* we found it!*/
379                 /*detach it from the free list*/
380 #ifdef DBG_QM_MALLOC
381                         qm_debug_frag(qm, f);
382 #endif
383                 qm_detach_free(qm, f);
384                 /*mark it as "busy"*/
385                 f->u.is_free=0;
386                 qm->free_hash[hash].no--;
387                 /* we ignore split return */
388 #ifdef DBG_QM_MALLOC
389                 split_frag(qm, f, size, file, "fragm. from qm_malloc", line);
390 #else
391                 split_frag(qm, f, size);
392 #endif
393                 qm->real_used+=f->size;
394                 qm->used+=f->size;
395                 if (qm->max_real_used<qm->real_used)
396                         qm->max_real_used=qm->real_used;
397 #ifdef DBG_QM_MALLOC
398                 f->file=file;
399                 f->func=func;
400                 f->line=line;
401                 f->check=ST_CHECK_PATTERN;
402                 /*  FRAG_END(f)->check1=END_CHECK_PATTERN1;
403                         FRAG_END(f)->check2=END_CHECK_PATTERN2;*/
404                 MDBG("qm_malloc(%p, %lu) returns address %p frag. %p (size=%lu) on %d"
405                                 " -th hit\n",
406                          qm, size, (char*)f+sizeof(struct qm_frag), f, f->size, list_cntr );
407 #endif
408                 return (char*)f+sizeof(struct qm_frag);
409         }
410         return 0;
411 }
412
413
414
415 #ifdef DBG_QM_MALLOC
416 void qm_free(struct qm_block* qm, void* p, const char* file, const char* func, 
417                                 unsigned int line)
418 #else
419 void qm_free(struct qm_block* qm, void* p)
420 #endif
421 {
422         struct qm_frag* f;
423         struct qm_frag* prev;
424         struct qm_frag* next;
425         unsigned long size;
426
427 #ifdef DBG_QM_MALLOC
428         MDBG("qm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
429         if (p>(void*)qm->last_frag_end || p<(void*)qm->first_frag){
430                 LOG(L_CRIT, "BUG: qm_free: bad pointer %p (out of memory block!) - "
431                                 "aborting\n", p);
432                 abort();
433         }
434 #endif
435         if (p==0) {
436                 LOG(L_WARN, "WARNING:qm_free: free(0) called\n");
437                 return;
438         }
439         prev=next=0;
440         f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
441 #ifdef DBG_QM_MALLOC
442         qm_debug_frag(qm, f);
443         if (f->u.is_free){
444                 LOG(L_CRIT, "BUG: qm_free: freeing already freed pointer,"
445                                 " first free: %s: %s(%ld) - aborting\n",
446                                 f->file, f->func, f->line);
447                 abort();
448         }
449         MDBG("qm_free: freeing frag. %p alloc'ed from %s: %s(%ld)\n",
450                         f, f->file, f->func, f->line);
451 #endif
452         size=f->size;
453         qm->used-=size;
454         qm->real_used-=size;
455
456 #ifdef QM_JOIN_FREE
457         /* mark this fragment as used (might fall into the middle of joined frags)
458           to give us an extra change of detecting a double free call (if the joined
459           fragment has not yet been reused) */
460         f->u.nxt_free=(void*)0x1L; /* bogus value, just to mark it as free */
461         /* join packets if possible*/
462         next=FRAG_NEXT(f);
463         if (((char*)next < (char*)qm->last_frag_end) &&( next->u.is_free)){
464                 /* join */
465 #ifdef DBG_QM_MALLOC
466                 qm_debug_frag(qm, next);
467 #endif
468                 qm_detach_free(qm, next);
469                 size+=next->size+FRAG_OVERHEAD;
470                 qm->real_used-=FRAG_OVERHEAD;
471                 qm->free_hash[GET_HASH(next->size)].no--; /* FIXME slow */
472         }
473         
474         if (f > qm->first_frag){
475                 prev=FRAG_PREV(f);
476                 /*      (struct qm_frag*)((char*)f - (struct qm_frag_end*)((char*)f-
477                                                                 sizeof(struct qm_frag_end))->size);*/
478 #ifdef DBG_QM_MALLOC
479                 qm_debug_frag(qm, prev);
480 #endif
481                 if (prev->u.is_free){
482                         /*join*/
483                         qm_detach_free(qm, prev);
484                         size+=prev->size+FRAG_OVERHEAD;
485                         qm->real_used-=FRAG_OVERHEAD;
486                         qm->free_hash[GET_HASH(prev->size)].no--; /* FIXME slow */
487                         f=prev;
488                 }
489         }
490         f->size=size;
491         FRAG_END(f)->size=f->size;
492 #endif /* QM_JOIN_FREE*/
493 #ifdef DBG_QM_MALLOC
494         f->file=file;
495         f->func=func;
496         f->line=line;
497 #endif
498         qm_insert_free(qm, f);
499 }
500
501
502
503 #ifdef DBG_QM_MALLOC
504 void* qm_realloc(struct qm_block* qm, void* p, unsigned long size,
505                                         const char* file, const char* func, unsigned int line)
506 #else
507 void* qm_realloc(struct qm_block* qm, void* p, unsigned long size)
508 #endif
509 {
510         struct qm_frag* f;
511         unsigned long diff;
512         unsigned long orig_size;
513         struct qm_frag* n;
514         void* ptr;
515         
516         
517 #ifdef DBG_QM_MALLOC
518         MDBG("qm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p, size,
519                         file, func, line);
520         if ((p)&&(p>(void*)qm->last_frag_end || p<(void*)qm->first_frag)){
521                 LOG(L_CRIT, "BUG: qm_free: bad pointer %p (out of memory block!) - "
522                                 "aborting\n", p);
523                 abort();
524         }
525 #endif
526         
527         if (size==0) {
528                 if (p)
529 #ifdef DBG_QM_MALLOC
530                         qm_free(qm, p, file, func, line);
531 #else
532                         qm_free(qm, p);
533 #endif
534                 return 0;
535         }
536         if (p==0)
537 #ifdef DBG_QM_MALLOC
538                 return qm_malloc(qm, size, file, func, line);
539 #else
540                 return qm_malloc(qm, size);
541 #endif
542         f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
543 #ifdef DBG_QM_MALLOC
544         qm_debug_frag(qm, f);
545         MDBG("qm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
546                         f, f->file, f->func, f->line);
547         if (f->u.is_free){
548                 LOG(L_CRIT, "BUG:qm_realloc: trying to realloc an already freed "
549                                 "pointer %p , fragment %p -- aborting\n", p, f);
550                 abort();
551         }
552 #endif
553         /* find first acceptable size */
554         size=ROUNDUP(size);
555         if (f->size > size){
556                 orig_size=f->size;
557                 /* shrink */
558 #ifdef DBG_QM_MALLOC
559                 MDBG("qm_realloc: shrinking from %lu to %lu\n", f->size, size);
560                 if(split_frag(qm, f, size, file, "fragm. from qm_realloc", line)!=0){
561                 MDBG("qm_realloc : shrinked successful\n");
562 #else
563                 if(split_frag(qm, f, size)!=0){
564 #endif
565                         /* update used sizes: freed the spitted frag */
566                         qm->real_used-=(orig_size-f->size-FRAG_OVERHEAD);
567                         qm->used-=(orig_size-f->size);
568                 }
569                 
570         }else if (f->size < size){
571                 /* grow */
572 #ifdef DBG_QM_MALLOC
573                 MDBG("qm_realloc: growing from %lu to %lu\n", f->size, size);
574 #endif
575                         orig_size=f->size;
576                         diff=size-f->size;
577                         n=FRAG_NEXT(f);
578                         if (((char*)n < (char*)qm->last_frag_end) && 
579                                         (n->u.is_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
580                                 /* join  */
581                                 qm_detach_free(qm, n);
582                                 qm->free_hash[GET_HASH(n->size)].no--; /*FIXME: slow*/
583                                 f->size+=n->size+FRAG_OVERHEAD;
584                                 qm->real_used-=FRAG_OVERHEAD;
585                                 FRAG_END(f)->size=f->size;
586                                 /* end checks should be ok */
587                                 /* split it if necessary */
588                                 if (f->size > size ){
589         #ifdef DBG_QM_MALLOC
590                                         split_frag(qm, f, size, file, "fragm. from qm_realloc",
591                                                                                 line);
592         #else
593                                         split_frag(qm, f, size);
594         #endif
595                                 }
596                                 qm->real_used+=(f->size-orig_size);
597                                 qm->used+=(f->size-orig_size);
598                         }else{
599                                 /* could not join => realloc */
600         #ifdef DBG_QM_MALLOC
601                                 ptr=qm_malloc(qm, size, file, func, line);
602         #else
603                                 ptr=qm_malloc(qm, size);
604         #endif
605                                 if (ptr){
606                                         /* copy, need by libssl */
607                                         memcpy(ptr, p, orig_size);
608         #ifdef DBG_QM_MALLOC
609                                         qm_free(qm, p, file, func, line);
610         #else
611                                         qm_free(qm, p);
612         #endif
613                                 }
614                                 p=ptr;
615                         }
616         }else{
617                 /* do nothing */
618 #ifdef DBG_QM_MALLOC
619                 MDBG("qm_realloc: doing nothing, same size: %lu - %lu\n",
620                                 f->size, size);
621 #endif
622         }
623 #ifdef DBG_QM_MALLOC
624         MDBG("qm_realloc: returning %p\n", p);
625 #endif
626         return p;
627 }
628
629
630 void qm_check(struct qm_block* qm)
631 {
632         struct qm_frag* f;
633         long fcount = 0;
634         int memlog;
635         
636         memlog=cfg_get(core, core_cfg, memlog);
637         LOG(memlog, "DEBUG: qm_check()\n");
638         f = qm->first_frag;
639         while ((char*)f < (char*)qm->last_frag_end) {
640                 fcount++;
641                 /* check struct qm_frag */
642 #ifdef DBG_QM_MALLOC
643                 if (f->check!=ST_CHECK_PATTERN){
644                         LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
645                                         "beginning overwritten(%lx)!\n",
646                                         f, (char*)f + sizeof(struct qm_frag),
647                                         f->check);
648                         qm_status(qm);
649                         abort();
650                 };
651 #endif
652                 if (f + sizeof(struct qm_frag) + f->size + sizeof(struct qm_frag_end) > qm->first_frag + qm->size) {
653                         LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
654                                 "bad size: %lu (frag end: %p > end of block: %p)\n",
655                                 f, (char*)f + sizeof(struct qm_frag) + sizeof(struct qm_frag_end), f->size,
656                                 f + sizeof(struct qm_frag) + f->size, qm->first_frag + qm->size);
657                         qm_status(qm);
658                         abort();
659                 }
660                 /* check struct qm_frag_end */
661                 if (FRAG_END(f)->size != f->size) {
662                         LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
663                                 "size in qm_frag and qm_frag_end does not match: frag->size=%lu, frag_end->size=%lu)\n",
664                                 f, (char*)f + sizeof(struct qm_frag),
665                                 f->size, FRAG_END(f)->size);
666                         qm_status(qm);
667                         abort();
668                 }
669 #ifdef DBG_QM_MALLOC
670                 if ((FRAG_END(f)->check1 != END_CHECK_PATTERN1) ||
671                         (FRAG_END(f)->check2 != END_CHECK_PATTERN2)) {
672                         LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p)"
673                                                 " end overwritten(%lx, %lx)!\n",
674                                         f, (char*)f + sizeof(struct qm_frag), 
675                                         FRAG_END(f)->check1, FRAG_END(f)->check2);
676                         qm_status(qm);
677                         abort();
678                 }
679 #endif
680                 f = FRAG_NEXT(f);
681         }
682
683         LOG(memlog, "DEBUG: qm_check: %lu fragments OK\n", fcount);
684 }
685
686 void qm_status(struct qm_block* qm)
687 {
688         struct qm_frag* f;
689         int i,j;
690         int h;
691         int unused;
692         int memlog;
693
694
695         memlog=cfg_get(core, core_cfg, memlog);
696         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ", "(%p):\n", qm);
697         if (!qm) return;
698
699         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ", "heap size= %lu\n",
700                         qm->size);
701         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
702                         "used= %lu, used+overhead=%lu, free=%lu\n",
703                         qm->used, qm->real_used, qm->size-qm->real_used);
704         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
705                         "max used (+overhead)= %lu\n", qm->max_real_used);
706         
707         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
708                         "dumping all alloc'ed. fragments:\n");
709         for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;f=FRAG_NEXT(f)
710                         ,i++){
711                 if (! f->u.is_free){
712                         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
713                                         "   %3d. %c  address=%p frag=%p size=%lu used=%d\n",
714                                 i,
715                                 (f->u.is_free)?'a':'N',
716                                 (char*)f+sizeof(struct qm_frag), f, f->size, FRAG_WAS_USED(f));
717 #ifdef DBG_QM_MALLOC
718                         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
719                                         "          %s from %s: %s(%ld)\n",
720                                 (f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
721                         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
722                                         "         start check=%lx, end check= %lx, %lx\n",
723                                 f->check, FRAG_END(f)->check1, FRAG_END(f)->check2);
724 #endif
725                 }
726         }
727         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
728                         "dumping free list stats :\n");
729         for(h=0,i=0;h<QM_HASH_SIZE;h++){
730                 unused=0;
731                 for (f=qm->free_hash[h].head.u.nxt_free,j=0; 
732                                 f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++){
733                                 if (!FRAG_WAS_USED(f)){
734                                         unused++;
735 #ifdef DBG_QM_MALLOC
736                                         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
737                                                 "unused fragm.: hash = %3d, fragment %p,"
738                                                 " address %p size %lu, created from %s: %s(%lu)\n",
739                                             h, f, (char*)f+sizeof(struct qm_frag), f->size,
740                                                 f->file, f->func, f->line);
741 #endif
742                                 }
743                 }
744
745                 if (j) LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
746                                 "hash= %3d. fragments no.: %5d, unused: %5d\n"
747                                         "\t\t bucket size: %9lu - %9ld (first %9lu)\n",
748                                         h, j, unused, UN_HASH(h),
749                                         ((h<=QM_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
750                                         qm->free_hash[h].head.u.nxt_free->size
751                                 );
752                 if (j!=qm->free_hash[h].no){
753                         LOG(L_CRIT, "BUG: qm_status: different free frag. count: %d!=%lu"
754                                 " for hash %3d\n", j, qm->free_hash[h].no, h);
755                 }
756
757         }
758         LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
759                         "-----------------------------\n");
760 }
761
762
763 /* fills a malloc info structure with info about the block
764  * if a parameter is not supported, it will be filled with 0 */
765 void qm_info(struct qm_block* qm, struct mem_info* info)
766 {
767         int r;
768         long total_frags;
769         
770         total_frags=0;
771         memset(info,0, sizeof(*info));
772         info->total_size=qm->size;
773         info->min_frag=MIN_FRAG_SIZE;
774         info->free=qm->size-qm->real_used;
775         info->used=qm->used;
776         info->real_used=qm->real_used;
777         info->max_used=qm->max_real_used;
778         for(r=0;r<QM_HASH_SIZE; r++){
779                 total_frags+=qm->free_hash[r].no;
780         }
781         info->total_frags=total_frags;
782 }
783
784
785 /* returns how much free memory is available
786  * it never returns an error (unlike fm_available) */
787 unsigned long qm_available(struct qm_block* qm)
788 {
789         return qm->size-qm->real_used;
790 }
791
792
793
794 #ifdef DBG_QM_MALLOC
795
796 typedef struct _mem_counter{
797         const char *file;
798         const char *func;
799         unsigned long line;
800         
801         unsigned long size;
802         int count;
803         
804         struct _mem_counter *next;
805 } mem_counter;
806
807 static mem_counter* get_mem_counter(mem_counter **root, struct qm_frag* f)
808 {
809         mem_counter *x;
810         if (!*root) goto make_new;
811         for(x=*root;x;x=x->next)
812                 if (x->file == f->file && x->func == f->func && x->line == f->line)
813                         return x;
814 make_new:       
815         x = malloc(sizeof(mem_counter));
816         x->file = f->file;
817         x->func = f->func;
818         x->line = f->line;
819         x->count = 0;
820         x->size = 0;
821         x->next = *root;
822         *root = x;
823         return x;
824 }
825
826
827
828 void qm_sums(struct qm_block* qm)
829 {
830         struct qm_frag* f;
831         int i;
832         mem_counter *root, *x;
833         int memlog;
834         
835         root=0;
836         if (!qm) return;
837         
838         memlog=cfg_get(core, core_cfg, memlog);
839         LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
840                         "summarizing all alloc'ed. fragments:\n");
841         
842         for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;
843                         f=FRAG_NEXT(f),i++){
844                 if (! f->u.is_free){
845                         x = get_mem_counter(&root,f);
846                         x->count++;
847                         x->size+=f->size;
848                 }
849         }
850         x = root;
851         while(x){
852                 LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
853                                 " count=%6d size=%10lu bytes from %s: %s(%ld)\n",
854                         x->count,x->size,
855                         x->file, x->func, x->line
856                         );
857                 root = x->next;
858                 free(x);
859                 x = root;
860         }
861         LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
862                         "-----------------------------\n");
863 }
864 #endif /* DBG_QM_MALLOC */
865
866
867 #endif