Asterisk - The Open Source Telephony Project  GIT-master-b7027de
stringfields.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Digium, Inc.
5  *
6  * Kevin P. Fleming <kpfleming@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief String fields
22  *
23  * \author Kevin P. Fleming <kpfleming@digium.com>
24  */
25 
26 #include "asterisk.h"
27 
28 #include "asterisk/stringfields.h"
29 #include "asterisk/utils.h"
30 
31 /* this is a little complex... string fields are stored with their
32  allocated size in the bytes preceding the string; even the
33  constant 'empty' string has to be this way, so the code that
34  checks to see if there is enough room for a new string doesn't
35  have to have any special case checks
36 */
37 
38 static const struct {
40  char string[1];
42 
44 
45 #define ALLOCATOR_OVERHEAD 48
46 
47 static size_t optimal_alloc_size(size_t size)
48 {
49  unsigned int count;
50 
51  size += ALLOCATOR_OVERHEAD;
52 
53  for (count = 1; size; size >>= 1, count++);
54 
55  return (1 << count) - ALLOCATOR_OVERHEAD;
56 }
57 
58 /*! \brief add a new block to the pool.
59  * We can only allocate from the topmost pool, so the
60  * fields in *mgr reflect the size of that only.
61  */
62 static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
63  size_t size, const char *file, int lineno, const char *func)
64 {
65  struct ast_string_field_pool *pool;
66  size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
67 
68  pool = __ast_calloc(1, alloc_size, file, lineno, func);
69  if (!pool) {
70  return -1;
71  }
72 
73  pool->prev = *pool_head;
74  pool->size = alloc_size - sizeof(*pool);
75  *pool_head = pool;
76  mgr->last_alloc = NULL;
77 
78  return 0;
79 }
80 
81 static void reset_field(const char **p)
82 {
84 }
85 
86 /*!
87  * \brief Internal cleanup function
88  * \internal
89  * \param mgr
90  * \param pool_head
91  * \param cleanup_type
92  * 0: Reset all string fields and free all pools except the last or embedded pool.
93  * Keep the internal management structures so the structure can be reused.
94  * -1: Reset all string fields and free all pools except the embedded pool.
95  * Free the internal management structures.
96  * \param file
97  * \param lineno
98  * \param func
99  *
100  * \retval 0 Success
101  * \retval -1 Failure
102  */
104  struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type,
105  const char *file, int lineno, const char *func)
106 {
107  struct ast_string_field_pool *cur = NULL;
108  struct ast_string_field_pool *preserve = NULL;
109 
110  /* reset all the fields regardless of cleanup type */
112 
113  switch (cleanup_type) {
116 
117  if (mgr->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */
118  preserve = mgr->embedded_pool;
119  preserve->used = preserve->active = 0;
120  }
121 
122  break;
124  /* Preserve the embedded pool if there is one, otherwise the last pool */
125  if (mgr->embedded_pool) {
126  preserve = mgr->embedded_pool;
127  } else {
128  if (*pool_head == NULL) {
129  ast_log(LOG_WARNING, "trying to reset empty pool\n");
130  return -1;
131  }
132  preserve = *pool_head;
133  }
134  preserve->used = preserve->active = 0;
135  break;
136  default:
137  return -1;
138  }
139 
140  cur = *pool_head;
141  while (cur) {
142  struct ast_string_field_pool *prev = cur->prev;
143 
144  if (cur != preserve) {
145  ast_free(cur);
146  }
147  cur = prev;
148  }
149 
150  *pool_head = preserve;
151  if (preserve) {
152  preserve->prev = NULL;
153  }
154 
155  return 0;
156 }
157 
158 /*!
159  * \brief Internal initialization function
160  * \internal
161  * \param mgr
162  * \param pool_head
163  * \param needed
164  * \param file
165  * \param lineno
166  * \param func
167  *
168  * \retval 0 Success
169  * \retval -1 Failure
170  */
172  int needed, const char *file, int lineno, const char *func)
173 {
174  const char **p = (const char **) pool_head + 1;
175  size_t initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
176 
177  if (needed <= 0) {
178  return __ast_string_field_free_memory(mgr, pool_head, needed, file, lineno, func);
179  }
180 
181  mgr->last_alloc = NULL;
182 
183  if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) {
184  return -1;
185  }
186 
187  while ((struct ast_string_field_mgr *) p != mgr) {
190  }
191 
192  *pool_head = NULL;
193  mgr->embedded_pool = NULL;
194  if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) {
196  return -1;
197  }
198 
199  return 0;
200 }
201 
203  struct ast_string_field_pool **pool_head, size_t needed,
204  const char *file, int lineno, const char *func)
205 {
206  char *result = NULL;
207  size_t space = (*pool_head)->size - (*pool_head)->used;
208  size_t to_alloc;
209 
210  /* Make room for ast_string_field_allocation and make it a multiple of that. */
213 
214  if (__builtin_expect(to_alloc > space, 0)) {
215  size_t new_size = (*pool_head)->size;
216 
217  while (new_size < to_alloc) {
218  new_size *= 2;
219  }
220 
221  if (add_string_pool(mgr, pool_head, new_size, file, lineno, func)) {
222  return NULL;
223  }
224  }
225 
226  /* pool->base is always aligned (gcc aligned attribute). We ensure that
227  * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation)
228  * causing result to always be aligned as well; which in turn fixes that
229  * AST_STRING_FIELD_ALLOCATION(result) is aligned. */
230  result = (*pool_head)->base + (*pool_head)->used;
231  (*pool_head)->used += to_alloc;
232  (*pool_head)->active += needed;
234  AST_STRING_FIELD_ALLOCATION(result) = needed;
235  mgr->last_alloc = result;
236 
237  return result;
238 }
239 
241  struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr)
242 {
243  ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
244  size_t space = (*pool_head)->size - (*pool_head)->used;
245 
246  if (*ptr != mgr->last_alloc) {
247  return 1;
248  }
249 
250  if (space < grow) {
251  return 1;
252  }
253 
254  (*pool_head)->used += grow;
255  (*pool_head)->active += grow;
257 
258  return 0;
259 }
260 
262  const ast_string_field ptr)
263 {
264  struct ast_string_field_pool *pool, *prev;
265 
266  if (ptr == __ast_string_field_empty) {
267  return;
268  }
269 
270  for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
271  if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
272  pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
273  if (pool->active == 0) {
274  if (prev) {
275  prev->prev = pool->prev;
276  ast_free(pool);
277  } else {
278  pool->used = 0;
279  }
280  }
281  break;
282  }
283  }
284 }
285 
287  struct ast_string_field_pool **pool_head, ast_string_field *ptr,
288  const char *format, va_list ap,
289  const char *file, int lineno, const char *func)
290 {
291  size_t needed;
292  size_t available;
293  size_t space = (*pool_head)->size - (*pool_head)->used;
294  int res;
295  ssize_t grow;
296  char *target;
297  va_list ap2;
298 
299  /* if the field already has space allocated, try to reuse it;
300  otherwise, try to use the empty space at the end of the current
301  pool
302  */
303  if (*ptr != __ast_string_field_empty) {
304  target = (char *) *ptr;
305  available = AST_STRING_FIELD_ALLOCATION(*ptr);
306  if (*ptr == mgr->last_alloc) {
307  available += space;
308  }
309  } else {
310  /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation)
311  * so we don't need to re-align anything here.
312  */
313  target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation);
315  available = space - ast_alignof(ast_string_field_allocation);
316  } else {
317  available = 0;
318  }
319  }
320 
321  va_copy(ap2, ap);
322  res = vsnprintf(target, available, format, ap2);
323  va_end(ap2);
324 
325  if (res < 0) {
326  /* Are we out of memory? */
327  return;
328  }
329  if (res == 0) {
330  __ast_string_field_release_active(*pool_head, *ptr);
332  return;
333  }
334  needed = (size_t)res + 1; /* NUL byte */
335 
336  if (needed > available) {
337  /* the allocation could not be satisfied using the field's current allocation
338  (if it has one), or the space available in the pool (if it does not). allocate
339  space for it, adding a new string pool if necessary.
340  */
341  target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed, file, lineno, func);
342  if (!target) {
343  return;
344  }
345  vsprintf(target, format, ap);
346  va_end(ap); /* XXX va_end without va_start? */
347  __ast_string_field_release_active(*pool_head, *ptr);
348  *ptr = target;
349  } else if (*ptr != target) {
350  /* the allocation was satisfied using available space in the pool, but not
351  using the space already allocated to the field
352  */
353  __ast_string_field_release_active(*pool_head, *ptr);
354  mgr->last_alloc = *ptr = target;
357  (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation);
358  (*pool_head)->active += needed;
359  } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
360  /* the allocation was satisfied by using available space in the pool *and*
361  the field was the last allocated field from the pool, so it grew
362  */
364  (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation);
365  (*pool_head)->active += grow;
366  }
367 }
368 
369 void __ast_string_field_ptr_build(const char *file, int lineno, const char *func,
370  struct ast_string_field_mgr *mgr,
371  struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, ...)
372 {
373  va_list ap;
374 
375  va_start(ap, format);
376  __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap, file, lineno, func);
377  va_end(ap);
378 }
379 
380 void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size,
381  size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size,
382  const char *file, int lineno, const char *func)
383 {
384  struct ast_string_field_mgr *mgr;
385  struct ast_string_field_pool *pool;
386  struct ast_string_field_pool **pool_head;
387  size_t pool_size_needed = sizeof(*pool) + pool_size;
388  size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
389  void *allocation;
390  const char **p;
391  size_t initial_vector_size;
392 
393  ast_assert(num_structs == 1);
394 
395  allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func);
396  if (!allocation) {
397  return NULL;
398  }
399 
400  mgr = allocation + field_mgr_offset;
401 
402  pool = allocation + struct_size;
403  pool_head = allocation + field_mgr_pool_offset;
404  p = (const char **) pool_head + 1;
405  initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
406 
407  if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) {
408  ast_free(allocation);
409  return NULL;
410  }
411 
412  while ((struct ast_string_field_mgr *) p != mgr) {
415  }
416 
417  mgr->embedded_pool = pool;
418  *pool_head = pool;
419  pool->size = size_to_alloc - struct_size - sizeof(*pool);
420 
421  return allocation;
422 }
423 
424 int __ast_string_fields_cmp(struct ast_string_field_vector *left,
425  struct ast_string_field_vector *right)
426 {
427  int i;
428  int res = 0;
429 
430  ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right));
431 
432  for (i = 0; i < AST_VECTOR_SIZE(left); i++) {
433  if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) {
434  return res;
435  }
436  }
437 
438  return res;
439 }
440 
442  struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr,
443  const char *file, int lineno, const char *func)
444 {
445  int i;
446  struct ast_string_field_vector *dest = &(copy_mgr->string_fields);
447  struct ast_string_field_vector *src = &(orig_mgr->string_fields);
448 
450 
451  for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
454  }
455 
456  for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
457  if (__ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i),
458  *AST_VECTOR_GET(src, i), file, lineno, func)) {
459  return -1;
460  }
461  }
462 
463  return 0;
464 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1635
Asterisk main include file. File version handling, generic pbx functions.
uint16_t ast_string_field_allocation
Definition: stringfields.h:194
#define ast_alignof(type)
Return the number of bytes used in the alignment of type.
Definition: utils.h:738
static void grow(struct ast_threadpool *pool, int delta)
Add threads to the threadpool.
Definition: threadpool.c:524
#define __ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data, file, lineno, func)
Definition: stringfields.h:479
struct ast_string_field_pool * embedded_pool
Definition: stringfields.h:229
#define LOG_WARNING
Definition: logger.h:274
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define ALLOCATOR_OVERHEAD
Definition: stringfields.c:45
int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type, const char *file, int lineno, const char *func)
Internal cleanup function.
Definition: stringfields.c:103
const char * ast_string_field
Definition: stringfields.h:190
#define ast_assert(a)
Definition: utils.h:710
void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, va_list ap, const char *file, int lineno, const char *func)
Definition: stringfields.c:286
void * __ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file, int lineno, const char *func)
Definition: stringfields.c:380
#define NULL
Definition: resample.c:96
static const struct @419 __ast_string_field_empty_buffer
struct ast_string_field_vector string_fields
Definition: stringfields.h:230
static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, size_t size, const char *file, int lineno, const char *func)
add a new block to the pool. We can only allocate from the topmost pool, so the fields in *mgr reflec...
Definition: stringfields.c:62
Utility functions.
#define AST_STRING_FIELD_ALLOCATION(x)
Macro to provide access to the allocation field that lives immediately in front of a string field...
Definition: stringfields.h:460
int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr)
Definition: stringfields.c:240
#define ast_log
Definition: astobj2.c:42
#define ast_make_room_for(offset, type)
Increase offset by the required alignment of type and make sure it is a multiple of said alignment...
Definition: utils.h:781
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static void reset_field(const char **p)
Definition: stringfields.c:81
static size_t optimal_alloc_size(size_t size)
Definition: stringfields.c:47
ast_string_field_allocation allocation
Definition: stringfields.c:39
ast_string_field __ast_string_field_empty
Definition: stringfields.c:43
int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, int needed, const char *file, int lineno, const char *func)
Internal initialization function.
Definition: stringfields.c:171
int __ast_string_fields_cmp(struct ast_string_field_vector *left, struct ast_string_field_vector *right)
Definition: stringfields.c:424
#define ast_free(a)
Definition: astmm.h:182
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13058
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, const ast_string_field ptr)
Definition: stringfields.c:261
ast_stringfield_cleanup_type
Definition: stringfields.h:309
static PGresult * result
Definition: cel_pgsql.c:88
struct ast_string_field_pool * prev
Definition: stringfields.h:209
void __ast_string_field_ptr_build(const char *file, int lineno, const char *func, struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format,...)
Definition: stringfields.c:369
#define ast_align_for(offset, type)
Increase offset so it is a multiple of the required alignment of type.
Definition: utils.h:758
int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool, struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr, const char *file, int lineno, const char *func)
Definition: stringfields.c:441
static snd_pcm_format_t format
Definition: chan_alsa.c:102
ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, size_t needed, const char *file, int lineno, const char *func)
Definition: stringfields.c:202
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
ast_string_field last_alloc
Definition: stringfields.h:228
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:865