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