Fix naming mismatch of allocator functions.
[asterisk/asterisk.git] / main / stringfields.c
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 ASTERISK_REGISTER_FILE()
29
30 #include "asterisk/stringfields.h"
31 #include "asterisk/utils.h"
32
33 /* this is a little complex... string fields are stored with their
34    allocated size in the bytes preceding the string; even the
35    constant 'empty' string has to be this way, so the code that
36    checks to see if there is enough room for a new string doesn't
37    have to have any special case checks
38 */
39
40 static const struct {
41         ast_string_field_allocation allocation;
42         char string[1];
43 } __ast_string_field_empty_buffer;
44
45 ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string;
46
47 #define ALLOCATOR_OVERHEAD 48
48
49 static size_t optimal_alloc_size(size_t size)
50 {
51         unsigned int count;
52
53         size += ALLOCATOR_OVERHEAD;
54
55         for (count = 1; size; size >>= 1, count++);
56
57         return (1 << count) - ALLOCATOR_OVERHEAD;
58 }
59
60 static void *calloc_wrapper(unsigned int num_structs, size_t struct_size,
61         const char *file, int lineno, const char *func)
62 {
63         return __ast_calloc(num_structs, struct_size, file, lineno, func);
64 }
65
66 /*! \brief add a new block to the pool.
67  * We can only allocate from the topmost pool, so the
68  * fields in *mgr reflect the size of that only.
69  */
70 static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
71         size_t size, const char *file, int lineno, const char *func)
72 {
73         struct ast_string_field_pool *pool;
74         size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
75
76         if (!(pool = calloc_wrapper(1, alloc_size, file, lineno, func))) {
77                 return -1;
78         }
79
80         pool->prev = *pool_head;
81         pool->size = alloc_size - sizeof(*pool);
82         *pool_head = pool;
83         mgr->last_alloc = NULL;
84
85         return 0;
86 }
87
88 static void reset_field(const char **p)
89 {
90         *p = __ast_string_field_empty;
91 }
92
93 /*!
94  * \brief Internal cleanup function
95  * \internal
96  * \param mgr
97  * \param pool_head
98  * \param cleanup_type
99  *           0: Reset all string fields and free all pools except the last or embedded pool.
100  *              Keep the internal management structures so the structure can be reused.
101  *          -1: Reset all string fields and free all pools except the embedded pool.
102  *              Free the internal management structures.
103  * \param file
104  * \param lineno
105  * \param func
106  *
107  * \retval 0 Success
108  * \retval -1 Failure
109  */
110 int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr,
111         struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type,
112         const char *file, int lineno, const char *func)
113 {
114         struct ast_string_field_pool *cur = NULL;
115         struct ast_string_field_pool *preserve = NULL;
116
117         /* reset all the fields regardless of cleanup type */
118         AST_VECTOR_CALLBACK_VOID(&mgr->string_fields, reset_field);
119
120         switch (cleanup_type) {
121         case AST_STRINGFIELD_DESTROY:
122                 AST_VECTOR_FREE(&mgr->string_fields);
123
124                 if (mgr->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */
125                         preserve = mgr->embedded_pool;
126                         preserve->used = preserve->active = 0;
127                 }
128
129                 break;
130         case AST_STRINGFIELD_RESET:
131                 /* Preserve the embedded pool if there is one, otherwise the last pool */
132                 if (mgr->embedded_pool) {
133                         preserve = mgr->embedded_pool;
134                 } else {
135                         if (*pool_head == NULL) {
136                                 ast_log(LOG_WARNING, "trying to reset empty pool\n");
137                                 return -1;
138                         }
139                         preserve = *pool_head;
140                 }
141                 preserve->used = preserve->active = 0;
142                 break;
143         default:
144                 return -1;
145         }
146
147         cur = *pool_head;
148         while (cur) {
149                 struct ast_string_field_pool *prev = cur->prev;
150
151                 if (cur != preserve) {
152                         ast_free(cur);
153                 }
154                 cur = prev;
155         }
156
157         *pool_head = preserve;
158         if (preserve) {
159                 preserve->prev = NULL;
160         }
161
162         return 0;
163 }
164
165 /*!
166  * \brief Internal initialization function
167  * \internal
168  * \param mgr
169  * \param pool_head
170  * \param needed
171  * \param file
172  * \param lineno
173  * \param func
174  *
175  * \retval 0 Success
176  * \retval -1 Failure
177  */
178 int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
179         int needed, const char *file, int lineno, const char *func)
180 {
181         const char **p = (const char **) pool_head + 1;
182         size_t initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
183
184         if (needed <= 0) {
185                 return __ast_string_field_free_memory(mgr, pool_head, needed, file, lineno, func);
186         }
187
188         mgr->last_alloc = NULL;
189 #if defined(__AST_DEBUG_MALLOC)
190         mgr->owner_file = file;
191         mgr->owner_func = func;
192         mgr->owner_line = lineno;
193 #endif
194
195         if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) {
196                 return -1;
197         }
198
199         while ((struct ast_string_field_mgr *) p != mgr) {
200                 AST_VECTOR_APPEND(&mgr->string_fields, p);
201                 *p++ = __ast_string_field_empty;
202         }
203
204         *pool_head = NULL;
205         mgr->embedded_pool = NULL;
206         if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) {
207                 AST_VECTOR_FREE(&mgr->string_fields);
208                 return -1;
209         }
210
211         return 0;
212 }
213
214 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
215         struct ast_string_field_pool **pool_head, size_t needed)
216 {
217         char *result = NULL;
218         size_t space = (*pool_head)->size - (*pool_head)->used;
219         size_t to_alloc;
220
221         /* Make room for ast_string_field_allocation and make it a multiple of that. */
222         to_alloc = ast_make_room_for(needed, ast_string_field_allocation);
223         ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0);
224
225         if (__builtin_expect(to_alloc > space, 0)) {
226                 size_t new_size = (*pool_head)->size;
227
228                 while (new_size < to_alloc) {
229                         new_size *= 2;
230                 }
231
232 #if defined(__AST_DEBUG_MALLOC)
233                 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
234                         return NULL;
235 #else
236                 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
237                         return NULL;
238 #endif
239         }
240
241         /* pool->base is always aligned (gcc aligned attribute). We ensure that
242          * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation)
243          * causing result to always be aligned as well; which in turn fixes that
244          * AST_STRING_FIELD_ALLOCATION(result) is aligned. */
245         result = (*pool_head)->base + (*pool_head)->used;
246         (*pool_head)->used += to_alloc;
247         (*pool_head)->active += needed;
248         result += ast_alignof(ast_string_field_allocation);
249         AST_STRING_FIELD_ALLOCATION(result) = needed;
250         mgr->last_alloc = result;
251
252         return result;
253 }
254
255 int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
256         struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr)
257 {
258         ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
259         size_t space = (*pool_head)->size - (*pool_head)->used;
260
261         if (*ptr != mgr->last_alloc) {
262                 return 1;
263         }
264
265         if (space < grow) {
266                 return 1;
267         }
268
269         (*pool_head)->used += grow;
270         (*pool_head)->active += grow;
271         AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
272
273         return 0;
274 }
275
276 void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
277         const ast_string_field ptr)
278 {
279         struct ast_string_field_pool *pool, *prev;
280
281         if (ptr == __ast_string_field_empty) {
282                 return;
283         }
284
285         for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
286                 if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
287                         pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
288                         if (pool->active == 0) {
289                                 if (prev) {
290                                         prev->prev = pool->prev;
291                                         ast_free(pool);
292                                 } else {
293                                         pool->used = 0;
294                                 }
295                         }
296                         break;
297                 }
298         }
299 }
300
301 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
302         struct ast_string_field_pool **pool_head, ast_string_field *ptr,
303         const char *format, va_list ap)
304 {
305         size_t needed;
306         size_t available;
307         size_t space = (*pool_head)->size - (*pool_head)->used;
308         int res;
309         ssize_t grow;
310         char *target;
311         va_list ap2;
312
313         /* if the field already has space allocated, try to reuse it;
314            otherwise, try to use the empty space at the end of the current
315            pool
316         */
317         if (*ptr != __ast_string_field_empty) {
318                 target = (char *) *ptr;
319                 available = AST_STRING_FIELD_ALLOCATION(*ptr);
320                 if (*ptr == mgr->last_alloc) {
321                         available += space;
322                 }
323         } else {
324                 /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation)
325                  * so we don't need to re-align anything here.
326                  */
327                 target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation);
328                 if (space > ast_alignof(ast_string_field_allocation)) {
329                         available = space - ast_alignof(ast_string_field_allocation);
330                 } else {
331                         available = 0;
332                 }
333         }
334
335         va_copy(ap2, ap);
336         res = vsnprintf(target, available, format, ap2);
337         va_end(ap2);
338
339         if (res < 0) {
340                 /* Are we out of memory? */
341                 return;
342         }
343         if (res == 0) {
344                 __ast_string_field_release_active(*pool_head, *ptr);
345                 *ptr = __ast_string_field_empty;
346                 return;
347         }
348         needed = (size_t)res + 1; /* NUL byte */
349
350         if (needed > available) {
351                 /* the allocation could not be satisfied using the field's current allocation
352                    (if it has one), or the space available in the pool (if it does not). allocate
353                    space for it, adding a new string pool if necessary.
354                 */
355                 if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) {
356                         return;
357                 }
358                 vsprintf(target, format, ap);
359                 va_end(ap); /* XXX va_end without va_start? */
360                 __ast_string_field_release_active(*pool_head, *ptr);
361                 *ptr = target;
362         } else if (*ptr != target) {
363                 /* the allocation was satisfied using available space in the pool, but not
364                    using the space already allocated to the field
365                 */
366                 __ast_string_field_release_active(*pool_head, *ptr);
367                 mgr->last_alloc = *ptr = target;
368                 ast_assert(needed < (ast_string_field_allocation)-1);
369                 AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed;
370                 (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation);
371                 (*pool_head)->active += needed;
372         } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
373                 /* the allocation was satisfied by using available space in the pool *and*
374                    the field was the last allocated field from the pool, so it grew
375                 */
376                 AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
377                 (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation);
378                 (*pool_head)->active += grow;
379         }
380 }
381
382 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
383         struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, ...)
384 {
385         va_list ap;
386
387         va_start(ap, format);
388         __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap);
389         va_end(ap);
390 }
391
392 void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size,
393         size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file,
394         int lineno, const char *func)
395 {
396         struct ast_string_field_mgr *mgr;
397         struct ast_string_field_pool *pool;
398         struct ast_string_field_pool **pool_head;
399         size_t pool_size_needed = sizeof(*pool) + pool_size;
400         size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
401         void *allocation;
402         const char **p;
403         size_t initial_vector_size;
404
405         ast_assert(num_structs == 1);
406
407         if (!(allocation = calloc_wrapper(num_structs, size_to_alloc, file, lineno, func))) {
408                 return NULL;
409         }
410
411         mgr = allocation + field_mgr_offset;
412
413         pool = allocation + struct_size;
414         pool_head = allocation + field_mgr_pool_offset;
415         p = (const char **) pool_head + 1;
416         initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
417
418         if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) {
419                 ast_free(allocation);
420                 return NULL;
421         }
422
423         while ((struct ast_string_field_mgr *) p != mgr) {
424                 AST_VECTOR_APPEND(&mgr->string_fields, p);
425                 *p++ = __ast_string_field_empty;
426         }
427
428         mgr->embedded_pool = pool;
429         *pool_head = pool;
430         pool->size = size_to_alloc - struct_size - sizeof(*pool);
431 #if defined(__AST_DEBUG_MALLOC)
432                 mgr->owner_file = file;
433                 mgr->owner_func = func;
434                 mgr->owner_line = lineno;
435 #endif
436
437         return allocation;
438 }
439
440 int __ast_string_fields_cmp(struct ast_string_field_vector *left,
441         struct ast_string_field_vector *right)
442 {
443         int i;
444         int res = 0;
445
446         ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right));
447
448         for (i = 0; i < AST_VECTOR_SIZE(left); i++) {
449                 if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) {
450                         return res;
451                 }
452         }
453
454         return res;
455 }
456
457 int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool,
458         struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr)
459 {
460         int i;
461         struct ast_string_field_vector *dest = &(copy_mgr->string_fields);
462         struct ast_string_field_vector *src = &(orig_mgr->string_fields);
463
464         ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src));
465
466         for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
467                 __ast_string_field_release_active(copy_pool, *AST_VECTOR_GET(dest, i));
468                 *AST_VECTOR_GET(dest, i) = __ast_string_field_empty;
469         }
470
471         for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
472                 if (ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i),
473                         *AST_VECTOR_GET(src, i))) {
474                         return -1;
475                 }
476         }
477
478         return 0;
479 }