/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 | | |