Coverage Report

Created: 2026-01-25 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/mem/f_parallel_malloc.c
Line
Count
Source
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
#ifdef F_PARALLEL_MALLOC
23
24
#include <string.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
28
#include "f_parallel_malloc.h"
29
#include "../dprint.h"
30
#include "../globals.h"
31
#include "../statistics.h"
32
33
#ifdef DBG_MALLOC
34
#include "mem_dbg_hash.h"
35
#endif
36
37
#include "../lib/dbg/struct_hist.h"
38
39
0
#define MIN_FRAG_SIZE ROUNDTO
40
0
#define F_PARALLEL_FRAG_OVERHEAD  (sizeof(struct parallel_frag))
41
0
#define frag_is_free(_f) ((_f)->prev)
42
#define frag_seems_valid(_f, _b) (!(_f)->prev || \
43
    ((_b)->first_frag <= *(_f)->prev && *(_f)->prev <= (_b)->last_frag))
44
45
#define F_PARALLEL_FRAG_NEXT(f) \
46
0
  ((struct parallel_frag *)((char *)(f) + sizeof(struct parallel_frag) + (f)->size))
47
48
#define max(a,b) ( (a)>(b)?(a):(b))
49
50
/* ROUNDTO= 2^k so the following works */
51
0
#define ROUNDTO_MASK  (~((unsigned long)ROUNDTO-1))
52
0
#define ROUNDUP(s)    (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
53
0
#define ROUNDDOWN(s)  ((s)&ROUNDTO_MASK)
54
55
/* finds the hash value for s, s=ROUNDTO multiple*/
56
0
#define F_PARALLEL_GET_HASH(s)   ( ((unsigned long)(s)<=F_PARALLEL_MALLOC_OPTIMIZE)?\
57
0
              (unsigned long)(s)/ROUNDTO: \
58
0
              F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
59
0
                F_PARALLEL_MALLOC_OPTIMIZE_FACTOR+1 )
60
61
0
#define F_PARALLEL_UN_HASH(h) ( ((unsigned long)(h)<=(F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO))?\
62
0
            (unsigned long)(h)*ROUNDTO: \
63
0
            1UL<<((unsigned long)(h)-F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO+\
64
0
              F_PARALLEL_MALLOC_OPTIMIZE_FACTOR-1)\
65
0
          )
66
67
static inline void parallel_free_minus(struct parallel_block *fm, unsigned long size)
68
0
{
69
70
0
  #if defined(DBG_MALLOC) || defined(STATISTICS)
71
0
  fm->real_used+=size;
72
0
  fm->used+=size;
73
0
  #endif
74
0
}
75
76
77
static inline void parallel_free_plus(struct parallel_block *fm, unsigned long size)
78
0
{
79
80
0
  #if defined(DBG_MALLOC) || defined(STATISTICS)
81
0
  fm->real_used-=size;
82
0
  fm->used-=size;
83
0
  #endif
84
0
}
85
86
87
/* computes hash number for big buckets*/
88
inline static unsigned long big_hash_idx(unsigned long s)
89
0
{
90
0
  unsigned long idx;
91
  /* s is rounded => s = k*2^n (ROUNDTO=2^n)
92
   * index= i such that 2^i > s >= 2^(i-1)
93
   *
94
   * => index = number of the first non null bit in s*/
95
0
  idx=sizeof(long)*8-1;
96
0
  for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
97
0
  return idx;
98
0
}
99
100
#ifdef SHM_EXTRA_STATS
101
#include "module_info.h"
102
unsigned long parallel_stats_get_index(void *ptr)
103
{
104
  if (!ptr)
105
    return GROUP_IDX_INVALID;
106
107
  return F_PARALLEL_FRAG(ptr)->statistic_index;
108
}
109
110
void parallel_stats_set_index(void *ptr, unsigned long idx)
111
{
112
  if (!ptr)
113
    return;
114
115
  F_PARALLEL_FRAG(ptr)->statistic_index = idx;
116
}
117
#endif
118
119
static inline void parallel_insert_free(struct parallel_block *fm, struct parallel_frag *frag)
120
0
{
121
0
  struct parallel_frag **f;
122
0
  int hash;
123
124
0
  hash=F_PARALLEL_GET_HASH(frag->size);
125
0
  f=&(fm->free_hash[hash].first);
126
0
  if (*f)
127
0
    (*f)->block_ptr = fm;
128
0
  if (frag->size > F_PARALLEL_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
129
                      (different from 0.8.1[24] on
130
                       purpose --andrei ) */
131
0
    for(; *f; f=&((*f)->u.nxt_free)){
132
0
      (*f)->block_ptr = fm;
133
0
      if (frag->size <= (*f)->size) break;
134
0
    }
135
0
  }
136
137
  /*insert it here*/
138
0
  if (*f) {
139
0
    (*f)->block_ptr = fm;
140
0
  }
141
142
0
  frag->prev = f;
143
0
  frag->u.nxt_free=*f;
144
0
  frag->block_ptr = fm;
145
146
0
  if( *f ) {
147
0
    (*f)->block_ptr = fm;
148
0
    (*f)->prev = &(frag->u.nxt_free);
149
0
    frag->u.nxt_free->block_ptr = fm;
150
0
  }
151
152
0
  *f=frag;
153
0
  fm->free_hash[hash].no++;
154
155
0
  frag->block_ptr = fm;
156
0
  parallel_free_plus(fm, frag->size);
157
0
}
158
159
static inline void parallel_remove_free(struct parallel_block *fm, struct parallel_frag *n)
160
0
{
161
0
  struct parallel_frag **pf;
162
0
  int hash;
163
164
0
  pf = n->prev;
165
0
  hash = F_PARALLEL_GET_HASH( n->size );
166
167
  /* detach */
168
0
  if (*pf)
169
0
    (*pf)->block_ptr=fm;
170
171
0
  *pf=n->u.nxt_free;
172
0
  if (*pf)
173
0
    (*pf)->block_ptr=fm;
174
175
0
  if( n->u.nxt_free )
176
0
    n->u.nxt_free->prev = pf;
177
178
0
  fm->free_hash[hash].no--;
179
180
0
  n->prev = NULL;
181
0
  n->block_ptr = fm;
182
183
0
  parallel_free_minus(fm , n->size);
184
185
0
};
186
187
188
189
190
191
/* init malloc and return a parallel_block*/
192
struct parallel_block *parallel_malloc_init(char *address, unsigned long size, char *name, int idx)
193
194
0
{
195
0
  char *start;
196
0
  char *end;
197
0
  struct parallel_block *fm;
198
0
  unsigned long init_overhead;
199
200
  /* make address and size multiple of 8*/
201
0
  start=(char*)ROUNDUP((unsigned long) address);
202
0
  LM_DBG("F_OPTIMIZE=%lu, /ROUNDTO=%lu, %lu-bytes aligned\n",
203
0
      F_PARALLEL_MALLOC_OPTIMIZE, F_PARALLEL_MALLOC_OPTIMIZE/ROUNDTO,
204
0
      (unsigned long)ROUNDTO);
205
0
  LM_DBG("F_HASH_SIZE=%lu, parallel_block size=%zu, frag_size=%zu\n",
206
0
      F_PARALLEL_HASH_SIZE, sizeof(struct parallel_block), sizeof(struct parallel_frag));
207
0
  LM_DBG("params (%p, %lu), start=%p\n", address, size, start);
208
209
0
  if (size<(unsigned long)(start-address)) return 0;
210
0
  size-=(start-address);
211
0
  if (size <(MIN_FRAG_SIZE+F_PARALLEL_FRAG_OVERHEAD)) return 0;
212
0
  size=ROUNDDOWN(size);
213
214
0
  init_overhead=(ROUNDUP(sizeof(struct parallel_block))+ 2 * F_PARALLEL_FRAG_OVERHEAD);
215
216
217
0
  if (size < init_overhead)
218
0
  {
219
    /* not enough mem to create our control structures !!!*/
220
0
    return 0;
221
0
  }
222
0
  end=start+size;
223
0
  fm=(struct parallel_block *)start;
224
0
  memset(fm, 0, sizeof(struct parallel_block));
225
0
  fm->name = name;
226
0
  fm->size=size;
227
228
0
  fm->idx = idx;
229
230
0
  #if defined(DBG_MALLOC) || defined(STATISTICS)
231
0
  fm->used=size-init_overhead;
232
0
  fm->real_used=size;
233
0
  fm->max_real_used=init_overhead;
234
0
  fm->fragments = 0;
235
0
  #endif
236
237
0
  fm->first_frag=(struct parallel_frag *)(start+ROUNDUP(sizeof(struct parallel_block)));
238
0
  fm->last_frag=(struct parallel_frag *)(end-sizeof(struct parallel_frag));
239
240
0
  fm->first_frag->block_ptr = fm;
241
0
  fm->last_frag->block_ptr = fm;
242
243
  /* init initial fragment*/
244
0
  fm->first_frag->size=size-init_overhead;
245
0
  fm->last_frag->size=0;
246
247
0
  fm->last_frag->prev=NULL;
248
0
  fm->first_frag->prev=NULL;
249
250
  /* link initial fragment into the free list*/
251
252
0
  parallel_insert_free(fm, fm->first_frag);
253
254
0
  return fm;
255
0
}
256
257
#include "f_parallel_malloc_dyn.h"
258
259
#if !defined INLINE_ALLOC && defined DBG_MALLOC
260
#undef DBG_MALLOC
261
#include "f_parallel_malloc_dyn.h"
262
#define DBG_MALLOC
263
#endif
264
265
#ifdef SHM_EXTRA_STATS
266
void parallel_stats_core_init(struct parallel_block *fm, int core_index)
267
{
268
  struct parallel_frag *f;
269
270
  for (f=fm->first_frag; (char *)f < (char *)fm->last_frag; f=F_PARALLEL_FRAG_NEXT(f))
271
    if (!frag_is_free(f))
272
      f->statistic_index = core_index;
273
}
274
275
#endif
276
277
278
279
280
/* fills a malloc info structure with info about the block
281
 * if a parameter is not supported, it will be filled with 0 */
282
void parallel_info(struct parallel_block *fm, struct mem_info *info)
283
0
{
284
0
  memset(info,0, sizeof(*info));
285
  /* TODO - Not implemented, need an array here */
286
0
  return;
287
0
}
288
289
#endif