Coverage Report

Created: 2025-08-28 06:16

/src/opensips/mem/f_parallel_malloc_dyn.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 * Copyright (C) 2025 OpenSIPS Project
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
/*
23
 * If you have to deal with the ifdef spaghetti, here are its requirements:
24
 *   - be able to compile an inlined allocator (fm_split_frag short)
25
 *   - be able to compile an inlined, dbg allocator (fm_split_frag long)
26
 *   - be able to compile multiple allocators (fm_split_frag short)
27
 *   - be able to compile multiple, dbg allocators
28
 *             (fm_split_frag_dbg + fm_split_frag long,
29
 *              requires x2 include, hence the "_dynamic" file suffix)
30
 *
31
 * The same idea applies to all below functions.
32
 */
33
34
static inline
35
#if !defined INLINE_ALLOC && defined DBG_MALLOC
36
void parallel_split_frag_dbg(struct parallel_block *fm, struct parallel_frag *frag,
37
                       unsigned long size,
38
                       const char *file, const char *func, unsigned int line)
39
#elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
40
void parallel_split_frag(struct parallel_block *fm, struct parallel_frag *frag,
41
                   unsigned long size)
42
#else
43
void parallel_split_frag(struct parallel_block *fm, struct parallel_frag *frag,
44
                   unsigned long size,
45
                   const char *file, const char *func, unsigned int line)
46
#endif
47
0
{
48
0
  unsigned long rest;
49
0
  struct parallel_frag *n;
50
51
0
  frag->block_ptr = fm;
52
53
0
  rest=frag->size-size;
54
  #ifdef MEM_FRAG_AVOIDANCE
55
  if ((rest> (F_PARALLEL_FRAG_OVERHEAD+F_PARALLEL_MALLOC_OPTIMIZE))||
56
    (rest>=(F_PARALLEL_FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
57
  #else
58
0
  if (rest>(F_PARALLEL_FRAG_OVERHEAD+MIN_FRAG_SIZE)){
59
0
  #endif
60
0
    frag->size=size;
61
    /*split the fragment*/
62
0
    n=F_PARALLEL_FRAG_NEXT(frag);
63
0
    n->block_ptr=fm;
64
0
    n->size=rest-F_PARALLEL_FRAG_OVERHEAD;
65
66
67
    /*
68
     * The real used memory does not increase, as the frag memory is not
69
     * freed from real_used. On the other hand, the used size should
70
     * decrease, because the new fragment is not "useful data" - razvanc
71
72
    #if defined(DBG_MALLOC) || defined(STATISTICS)
73
    fm->real_used+=F_PARALLEL_FRAG_OVERHEAD;
74
    #endif
75
76
     */
77
0
    #if defined(DBG_MALLOC) || defined(STATISTICS)
78
0
    fm->used-=F_PARALLEL_FRAG_OVERHEAD;
79
0
    #endif
80
81
    #ifdef DBG_MALLOC
82
    /* frag created by malloc, mark it*/
83
    n->file=file;
84
    n->func=func;
85
    n->line=line;
86
    #endif
87
    /* reinsert n in free list*/
88
0
    parallel_insert_free(fm, n);
89
0
  }else{
90
    /* we cannot split this fragment any more => alloc all of it*/
91
0
  }
92
0
}
93
94
#if !defined INLINE_ALLOC && defined DBG_MALLOC
95
void *parallel_malloc_dbg(struct parallel_block *fm, unsigned long size,
96
                    const char *file, const char *func, unsigned int line)
97
#elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
98
void *parallel_malloc(struct parallel_block *fm, unsigned long size)
99
#else
100
void *parallel_malloc(struct parallel_block *fm, unsigned long size,
101
                const char *file, const char *func, unsigned int line)
102
#endif
103
0
{
104
0
  struct parallel_frag *frag, *n;
105
0
  unsigned int hash;
106
0
  int bucket;
107
108
0
  if (init_done == 0) {
109
0
    fm = shm_blocks[0];
110
0
  } else {
111
0
    bucket = rand() % TOTAL_F_PARALLEL_POOLS;
112
0
    fm = shm_blocks[bucket];
113
0
    lock_get(hash_locks[fm->idx]);
114
0
  }
115
116
  #ifdef DBG_MALLOC
117
  LM_GEN1(memlog, "%s_malloc(%lu), called from %s: %s(%d)\n", fm->name, size, file, func,
118
      line);
119
  #endif
120
121
  /*size must be a multiple of 8*/
122
0
  size=ROUNDUP(size);
123
124
  /*search for a suitable free frag*/
125
126
0
  for(hash=F_PARALLEL_GET_HASH(size);hash<F_PARALLEL_HASH_SIZE;hash++){
127
0
    frag=fm->free_hash[hash].first;
128
0
    for( ; frag; frag = frag->u.nxt_free ) {
129
0
      if ( frag->size >= size ) goto found;
130
    /* try in a bigger bucket */
131
0
    }
132
0
  }
133
  /* not found, bad! */
134
135
0
#if defined(DBG_MALLOC) || defined(STATISTICS)
136
0
  LM_WARN("not enough contiguous free %s memory (%ld bytes left, need %lu), attempting " \
137
0
      "defragmentation... please increase the \"-%s\" command line parameter!\n",
138
0
      fm->name, fm->size - fm->real_used, size, fm->name[0] == 'p' ? "M" : "m");
139
#else
140
  LM_WARN("not enough contiguous free %s memory (need %lu), attempting defragmentation... " \
141
      "please increase the \"-%s\" command line parameter!\n",
142
      fm->name, fm->size - fm->real_used, size, fm->name[0] == 'p' ? "M" : "m");
143
#endif
144
145
0
  for( frag = fm->first_frag; (char*)frag < (char*)fm->last_frag;  )
146
0
  {
147
0
    n = F_PARALLEL_FRAG_NEXT(frag);
148
149
0
    if (((char*)n < (char*)fm->last_frag) &&
150
0
        frag_is_free(n) && frag_is_free(frag))
151
0
    {
152
      /* detach frag*/
153
0
      parallel_remove_free(fm, frag);
154
155
0
      do
156
0
      {
157
0
        parallel_remove_free(fm, n);
158
0
        frag->size += n->size + F_PARALLEL_FRAG_OVERHEAD;
159
160
0
        #if defined(DBG_MALLOC) || defined(STATISTICS)
161
        //fm->real_used -= F_PARALLEL_FRAG_OVERHEAD;
162
0
        fm->used += F_PARALLEL_FRAG_OVERHEAD;
163
0
        #endif
164
165
0
        if (frag->size >size)
166
0
          goto solved;
167
168
0
        n = F_PARALLEL_FRAG_NEXT(frag);
169
0
      }
170
0
      while
171
0
      ( ((char*)n < (char*)fm->last_frag) && frag_is_free(n));
172
173
0
      parallel_insert_free(fm,frag);
174
175
0
    }
176
177
0
    frag = n;
178
0
  }
179
180
0
#if defined(DBG_MALLOC) || defined(STATISTICS)
181
0
  LM_ERR(oom_errorf, fm->name, fm->size - fm->real_used, size,
182
0
      fm->name[0] == 'p' ? "M" : "m");
183
#else
184
  LM_ERR(oom_nostats_errorf, fm->name, size, fm->name[0] == 'p' ? "M" : "m");
185
#endif
186
187
0
  if (init_done) { 
188
0
    lock_release(hash_locks[fm->idx]);
189
0
  }
190
0
  return 0;
191
192
193
0
found:
194
  /* we found it!*/
195
0
  parallel_remove_free(fm,frag);
196
197
  /*see if we'll use full frag, or we'll split it in 2*/
198
199
  #if !defined INLINE_ALLOC && defined DBG_MALLOC
200
  parallel_split_frag_dbg(fm, frag, size, file, "fm_malloc frag", line);
201
  #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
202
  parallel_split_frag(fm, frag, size);
203
  #else
204
  parallel_split_frag(fm, frag, size, file, "fm_malloc frag", line);
205
  #endif
206
207
  #ifdef DBG_MALLOC
208
  frag->file=file;
209
  frag->func=func;
210
  frag->line=line;
211
  LM_GEN1(memlog, "%s_malloc(%lu), returns address %p\n", fm->name, size,
212
    (char*)frag+sizeof(struct parallel_frag));
213
  #endif
214
215
0
solved:
216
217
0
  #if defined(DBG_MALLOC) || defined(STATISTICS)
218
0
  if (fm->max_real_used<fm->real_used)
219
0
    fm->max_real_used=fm->real_used;
220
0
  fm->fragments += 1;
221
0
  #endif
222
223
0
  frag->block_ptr = fm;
224
0
  if (init_done) {
225
0
    lock_release(hash_locks[fm->idx]);
226
0
  }
227
228
0
  return (char*)frag+sizeof(struct parallel_frag);
229
0
}
230
231
#if !defined INLINE_ALLOC && defined DBG_MALLOC
232
void parallel_free_dbg(struct parallel_block *fm, void *p, const char *file,
233
                 const char *func, unsigned int line)
234
#elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
235
void parallel_free(struct parallel_block *fm, void *p)
236
#else
237
void parallel_free(struct parallel_block *fm, void *p, const char *file,
238
             const char *func, unsigned int line)
239
#endif
240
0
{
241
0
  struct parallel_frag *f, *n;
242
243
  #ifdef DBG_MALLOC
244
  LM_GEN1(memlog, "%s_free(%p), called from %s: %s(%d)\n", fm->name, p, file,
245
          func, line);
246
  if (p && (p > (void *)fm->last_frag || p < (void *)fm->first_frag)) {
247
    LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
248
    abort();
249
  }
250
  #endif
251
0
  if (!p) {
252
0
    LM_GEN1(memlog, "free(NULL) called\n");
253
0
    return;
254
0
  }
255
256
0
  f = F_PARALLEL_FRAG(p);
257
0
  fm = f->block_ptr;
258
259
0
  lock_get(hash_locks[fm->idx]);
260
261
0
  check_double_free(p, f, fm);
262
263
#ifdef DBG_MALLOC
264
  LM_GEN1(memlog, "freeing block alloc'ed from %s: %s(%ld)\n",
265
          f->file, f->func, f->line);
266
#endif
267
268
  /* attempt to join with a next fragment that also happens to be free */
269
0
  n = F_PARALLEL_FRAG_NEXT(f);
270
0
  if (((char*)n < (char*)fm->last_frag) &&  frag_is_free(n)) {
271
0
    parallel_remove_free(fm, n);
272
    /* join */
273
0
    f->size += n->size + F_PARALLEL_FRAG_OVERHEAD;
274
275
0
    #if defined(DBG_MALLOC) || defined(STATISTICS)
276
    //fm->real_used -= F_PARALLEL_FRAG_OVERHEAD;
277
0
    fm->used += F_PARALLEL_FRAG_OVERHEAD;
278
0
    #endif
279
0
  }
280
281
#ifdef DBG_MALLOC
282
  f->file = file;
283
  f->func = func;
284
  f->line = line;
285
#endif
286
287
0
  parallel_insert_free(fm, f);
288
0
#if defined(DBG_MALLOC) || defined(STATISTICS)
289
0
  fm->fragments -= 1;
290
0
#endif
291
0
  lock_release(hash_locks[fm->idx]);
292
0
}
293
294
#if !defined INLINE_ALLOC && defined DBG_MALLOC
295
void parallel_free_dbg_unsafe(struct parallel_block *fm, void *p, const char *file,
296
                 const char *func, unsigned int line)
297
#elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
298
void parallel_free_unsafe(struct parallel_block *fm, void *p)
299
#else
300
void parallel_free_unsafe(struct parallel_block *fm, void *p, const char *file,
301
             const char *func, unsigned int line)
302
#endif
303
0
{
304
0
  struct parallel_frag *f, *n;
305
306
  #ifdef DBG_MALLOC
307
  LM_GEN1(memlog, "%s_free(%p), called from %s: %s(%d)\n", fm->name, p, file,
308
          func, line);
309
  if (p && (p > (void *)fm->last_frag || p < (void *)fm->first_frag)) {
310
    LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
311
    abort();
312
  }
313
  #endif
314
0
  if (!p) {
315
0
    LM_GEN1(memlog, "free(NULL) called\n");
316
0
    return;
317
0
  }
318
319
0
  f = F_PARALLEL_FRAG(p);
320
0
  fm = f->block_ptr;
321
322
0
  lock_get(hash_locks[fm->idx]);
323
0
  check_double_free(p, f, fm);
324
325
#ifdef DBG_MALLOC
326
  LM_GEN1(memlog, "freeing block alloc'ed from %s: %s(%ld)\n",
327
          f->file, f->func, f->line);
328
#endif
329
330
  /* attempt to join with a next fragment that also happens to be free */
331
0
  n = F_PARALLEL_FRAG_NEXT(f);
332
0
  if (((char*)n < (char*)fm->last_frag) &&  frag_is_free(n)) {
333
0
    parallel_remove_free(fm, n);
334
    /* join */
335
0
    f->size += n->size + F_PARALLEL_FRAG_OVERHEAD;
336
337
0
    #if defined(DBG_MALLOC) || defined(STATISTICS)
338
    //fm->real_used -= F_PARALLEL_FRAG_OVERHEAD;
339
0
    fm->used += F_PARALLEL_FRAG_OVERHEAD;
340
0
    #endif
341
0
  }
342
343
#ifdef DBG_MALLOC
344
  f->file = file;
345
  f->func = func;
346
  f->line = line;
347
#endif
348
349
0
  parallel_insert_free(fm, f);
350
0
#if defined(DBG_MALLOC) || defined(STATISTICS)
351
0
  fm->fragments -= 1;
352
0
#endif
353
0
  lock_release(hash_locks[fm->idx]);
354
0
}
355
356
357
358
#if !defined INLINE_ALLOC && defined DBG_MALLOC
359
void *parallel_realloc_dbg(struct parallel_block *fm, void *p, unsigned long size,
360
                     const char *file, const char *func, unsigned int line)
361
#elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
362
void *parallel_realloc(struct parallel_block *fm, void *p, unsigned long size)
363
#else
364
void *parallel_realloc(struct parallel_block *fm, void *p, unsigned long size,
365
                 const char *file, const char *func, unsigned int line)
366
#endif
367
0
{
368
0
  struct parallel_frag *f;
369
0
  unsigned long diff;
370
0
  unsigned long orig_size;
371
0
  struct parallel_frag *n;
372
0
  void *ptr,*input;
373
0
  int bucket;
374
375
0
  input = p;
376
377
0
  if (p) {
378
0
    fm = F_PARALLEL_FRAG(p)->block_ptr;
379
0
  } else {
380
0
    bucket = rand() % TOTAL_F_PARALLEL_POOLS;
381
0
    fm = shm_blocks[bucket];
382
0
  }
383
384
  #ifdef DBG_MALLOC
385
  LM_GEN1(memlog, "%s_realloc(%p, %lu->%lu), called from %s: %s(%d)\n",
386
          fm->name, p, p ? F_PARALLEL_FRAG(p)->size : 0, size, file, func, line);
387
  if (p && (p > (void *)fm->last_frag || p < (void *)fm->first_frag)) {
388
    LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
389
    abort();
390
  }
391
  #endif
392
393
0
  if (size == 0) {
394
0
    if (p) {
395
      #if !defined INLINE_ALLOC && defined DBG_MALLOC
396
      parallel_free_dbg(fm, p, file, func, line);
397
      #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
398
      parallel_free(fm, p);
399
      #else
400
      parallel_free(fm, p, file, func, line);
401
      #endif
402
0
    }
403
404
0
    return 0;
405
0
  }
406
407
0
  if (!p) {
408
    #if !defined INLINE_ALLOC && defined DBG_MALLOC
409
    return parallel_malloc_dbg(fm, size, file, func, line);
410
    #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
411
    return parallel_malloc(fm, size);
412
    #else
413
    return parallel_malloc(fm, size, file, func, line);
414
    #endif
415
0
  }
416
417
0
  lock_get(hash_locks[fm->idx]);
418
0
  f = F_PARALLEL_FRAG(p);
419
420
  #ifdef DBG_MALLOC
421
  LM_GEN1(memlog, "realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
422
      f, f->file, f->func, f->line);
423
  #endif
424
425
0
  size = ROUNDUP(size);
426
0
  orig_size = f->size;
427
428
0
  if (f->size > size) {
429
    /* shrink */
430
    #ifdef DBG_MALLOC
431
    LM_GEN1(memlog, "shrinking from %lu to %lu\n", f->size, size);
432
    #endif
433
434
    #if !defined INLINE_ALLOC && defined DBG_MALLOC
435
    parallel_split_frag_dbg(fm, f, size, file, "fm_realloc frag", line);
436
    #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
437
    parallel_split_frag(fm, f, size);
438
    #else
439
    parallel_split_frag(fm, f, size, file, "fm_realloc frag", line);
440
    #endif
441
442
0
  } else if (f->size < size) {
443
    /* grow */
444
    #ifdef DBG_MALLOC
445
    LM_GEN1(memlog, "growing from %lu to %lu\n", f->size, size);
446
    #endif
447
448
0
    diff = size-f->size;
449
0
    n = F_PARALLEL_FRAG_NEXT(f);
450
0
    n->block_ptr = fm;
451
452
0
    if (((char*)n < (char*)fm->last_frag) && frag_is_free(n) &&
453
0
     ((n->size+F_PARALLEL_FRAG_OVERHEAD)>=diff)) {
454
0
      parallel_remove_free(fm,n);
455
      /* join */
456
0
      f->size += n->size + F_PARALLEL_FRAG_OVERHEAD;
457
458
0
      #if defined(DBG_MALLOC) || defined(STATISTICS)
459
      //fm->real_used -= F_PARALLEL_FRAG_OVERHEAD;
460
0
      fm->used += F_PARALLEL_FRAG_OVERHEAD;
461
0
      #endif
462
463
      /* split it if necessary */
464
0
      if (f->size > size){
465
        #if !defined INLINE_ALLOC && defined DBG_MALLOC
466
        parallel_split_frag_dbg(fm, f, size, file, "fm_realloc frag", line);
467
        #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
468
        parallel_split_frag(fm, f, size);
469
        #else
470
        parallel_split_frag(fm, f, size, file, "fm_realloc frag", line);
471
        #endif
472
0
      }
473
0
    } else {
474
0
      lock_release(hash_locks[fm->idx]);
475
476
      /* could not join => realloc */
477
478
      #if !defined INLINE_ALLOC && defined DBG_MALLOC
479
      ptr = parallel_malloc_dbg(fm, size, file, func, line);
480
      #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
481
      ptr = parallel_malloc(fm, size);
482
      #else
483
      ptr = parallel_malloc(fm, size, file, func, line);
484
      #endif
485
486
0
      if (ptr) {
487
        /* copy, need by libssl */
488
0
        memcpy(ptr, p, orig_size);
489
490
        #if !defined INLINE_ALLOC && defined DBG_MALLOC
491
        parallel_free_dbg(fm, p, file, func, line);
492
        #elif !defined F_PARALLEL_MALLOC_DYN && !defined DBG_MALLOC
493
        parallel_free(fm, p);
494
        #else
495
        parallel_free(fm, p, file, func, line);
496
        #endif
497
0
      }
498
0
      p = ptr;
499
0
    }
500
0
  } else {
501
    /* do nothing */
502
    #ifdef DBG_MALLOC
503
    LM_GEN1(memlog, "doing nothing, same size: %lu - %lu\n", f->size, size);
504
    #endif
505
0
  }
506
507
  #ifdef DBG_MALLOC
508
  LM_GEN1(memlog, "returning %p\n", p);
509
  #endif
510
511
0
  #if defined(DBG_MALLOC) || defined(STATISTICS)
512
0
  if (fm->max_real_used<fm->real_used)
513
0
    fm->max_real_used=fm->real_used;
514
0
  #endif
515
516
0
  f->block_ptr = fm;
517
518
0
  if (input) {
519
0
    lock_release(hash_locks[fm->idx]);
520
0
  }
521
522
0
  return p;
523
0
}
524
525
#if !defined INLINE_ALLOC && defined DBG_MALLOC
526
void parallel_status_dbg(struct parallel_block *fm)
527
#else
528
void parallel_status(struct parallel_block *fm)
529
#endif
530
0
{
531
0
  struct parallel_frag *f;
532
0
  unsigned int i,j,bucket;
533
0
  unsigned int h;
534
0
  int unused;
535
0
  unsigned long size;
536
537
#ifdef DBG_MALLOC
538
  mem_dbg_htable_t allocd;
539
  struct mem_dbg_entry *it;
540
#endif
541
542
0
  for (bucket=0;bucket<TOTAL_F_PARALLEL_POOLS;bucket++) {
543
0
    fm = shm_blocks[bucket]; 
544
0
    lock_get(hash_locks[fm->idx]);
545
546
0
    LM_GEN1(memdump, "fm_status (%p):\n", fm);
547
0
    if (!fm) return;
548
549
0
    LM_GEN1(memdump, " heap size= %ld\n", fm->size);
550
0
#if defined(DBG_MALLOC) || defined(STATISTICS)
551
0
    LM_GEN1(memdump, " used= %lu, used+overhead=%lu, free=%lu\n",
552
0
        fm->used, fm->real_used, fm->size-fm->used);
553
0
    LM_GEN1(memdump, " max used (+overhead)= %lu\n", fm->max_real_used);
554
0
#endif
555
556
#if defined(DBG_MALLOC)
557
    dbg_ht_init(allocd);
558
559
    for (f = fm->first_frag; f >= fm->first_frag && f < fm->last_frag;
560
      f = F_PARALLEL_FRAG_NEXT(f)) {
561
      if (!frag_is_free(f) && f->file)
562
        if (dbg_ht_update(allocd, f->file, f->func, f->line, f->size) < 0) {
563
          LM_ERR("Unable to update alloc'ed. memory summary\n");
564
          dbg_ht_free(allocd);
565
          return;
566
        }
567
    }
568
569
    if (f != fm->last_frag)
570
      LM_GEN1(memdump, "failed to walk through all fragments (%p %p %p)\n",
571
        f, fm->first_frag, fm->last_frag);
572
573
    LM_GEN1(memdump, " dumping summary of all alloc'ed. fragments:\n");
574
    LM_GEN1(memdump, "------------+---------------------------------------\n");
575
    LM_GEN1(memdump, "total_bytes | num_allocations x [file: func, line]\n");
576
    LM_GEN1(memdump, "------------+---------------------------------------\n");
577
    for(i=0; i < DBG_HASH_SIZE; i++) {
578
      it = allocd[i];
579
      while (it) {
580
        LM_GEN1(memdump, " %10lu : %lu x [%s: %s, line %lu]\n",
581
          it->size, it->no_fragments, it->file, it->func, it->line);
582
        it = it->next;
583
      }
584
    }
585
    LM_GEN1(memdump, "----------------------------------------------------\n");
586
587
    dbg_ht_free(allocd);
588
#endif
589
590
0
    LM_GEN1(memdump, "dumping free list:\n");
591
0
    for(h=0,i=0,size=0;h<F_PARALLEL_HASH_SIZE;h++){
592
0
      unused=0;
593
0
      for (f=fm->free_hash[h].first,j=0; f;
594
0
          size+=f->size,f=f->u.nxt_free,i++,j++){ }
595
0
      if (j) LM_GEN1(memdump,"hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
596
0
                " bucket size: %9lu - %9lu (first %9lu)\n",
597
0
                h, j, unused, F_PARALLEL_UN_HASH(h),
598
0
              ((h<=F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* F_PARALLEL_UN_HASH(h),
599
0
                fm->free_hash[h].first->size
600
0
          );
601
0
      if (j!=fm->free_hash[h].no){
602
0
        LM_CRIT("different free frag. count: %d!=%ld"
603
0
            " for hash %3d\n", j, fm->free_hash[h].no, h);
604
0
      }
605
606
0
    }
607
0
    LM_GEN1(memdump, "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
608
0
    LM_GEN1(memdump, "TOTAL: %u overhead\n", (unsigned int)F_PARALLEL_FRAG_OVERHEAD );
609
0
    LM_GEN1(memdump, "-----------------------------\n");
610
611
0
    lock_release(hash_locks[fm->idx]);
612
0
  }
613
0
}
614
615
#define F_PARALLEL_MALLOC_DYN
616