Asterisk - The Open Source Telephony Project GIT-master-2de1a68
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
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
38static const struct {
40 char string[1];
42
44
45#define ALLOCATOR_OVERHEAD 48
46
47static 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 */
62static 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
81static 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;
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))) {
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;
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);
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
369void __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
380void *__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)) {
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
425 struct ast_string_field_vector *right)
426{
427 int i;
428 int res = 0;
429
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}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1603
#define ast_log
Definition: astobj2.c:42
static PGresult * result
Definition: cel_pgsql.c:84
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13451
#define LOG_WARNING
#define NULL
Definition: resample.c:96
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
static const struct @403 __ast_string_field_empty_buffer
int __ast_string_fields_cmp(struct ast_string_field_vector *left, struct ast_string_field_vector *right)
Definition: stringfields.c:424
static void reset_field(const char **p)
Definition: stringfields.c:81
void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, const ast_string_field ptr)
Definition: stringfields.c:261
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
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
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
ast_string_field_allocation allocation
Definition: stringfields.c:39
ast_string_field __ast_string_field_empty
Definition: stringfields.c:43
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
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 ALLOCATOR_OVERHEAD
Definition: stringfields.c:45
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
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
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
static size_t optimal_alloc_size(size_t size)
Definition: stringfields.c:47
#define __ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data, file, lineno, func)
Definition: stringfields.h:484
uint16_t ast_string_field_allocation
Definition: stringfields.h:194
ast_stringfield_cleanup_type
Definition: stringfields.h:313
@ AST_STRINGFIELD_DESTROY
Definition: stringfields.h:325
@ AST_STRINGFIELD_RESET
Definition: stringfields.h:318
const char * ast_string_field
Definition: stringfields.h:190
#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:465
struct ast_string_field_vector string_fields
Definition: stringfields.h:230
struct ast_string_field_pool * embedded_pool
Definition: stringfields.h:229
ast_string_field last_alloc
Definition: stringfields.h:228
struct ast_string_field_pool * prev
Definition: stringfields.h:209
static void grow(struct ast_threadpool *pool, int delta)
Add threads to the threadpool.
Definition: threadpool.c:525
Utility functions.
#define ast_assert(a)
Definition: utils.h:739
#define ast_align_for(offset, type)
Increase offset so it is a multiple of the required alignment of type.
Definition: utils.h:785
#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:808
#define ast_alignof(type)
Return the number of bytes used in the alignment of type.
Definition: utils.h:765
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680