2 Samba Unix SMB/CIFS implementation.
3 Samba temporary memory allocation functions
4 Copyright (C) Andrew Tridgell 2000
5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
7 This program 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.
12 This program 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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
23 @defgroup talloc Simple memory allocator
26 This is a very simple temporary memory allocator. To use it do the following:
28 1) when you first want to allocate a pool of meomry use
29 talloc_init() and save the resulting context pointer somewhere
31 2) to allocate memory use talloc()
33 3) when _all_ of the memory allocated using this context is no longer needed
36 talloc does not zero the memory. It guarantees memory of a
37 TALLOC_ALIGN alignment
43 * @todo We could allocate both the talloc_chunk structure, and the
44 * memory it contains all in one allocation, which might be a bit
45 * faster and perhaps use less memory overhead.
47 * That smells like a premature optimization, though. -- mbp
51 * If you want testing for memory corruption, link with dmalloc or use
52 * Insure++. It doesn't seem useful to duplicate them here.
58 struct talloc_chunk *next;
65 struct talloc_chunk *list;
66 off_t total_alloc_size;
68 /** The name recorded for this pool, if any. Should describe
69 * the purpose for which it was allocated. The string is
70 * allocated within the pool. **/
73 /** Pointer to the next allocate talloc pool, so that we can
74 * summarize all talloc memory usage. **/
75 struct talloc_ctx *next, *prev;
80 * Start of linked list of all talloc pools.
82 * @todo We should turn the global list off when using Insure++,
83 * otherwise all the memory will be seen as still reachable.
85 static TALLOC_CTX *list_head;
88 * Add to the global list
90 static void talloc_enroll(TALLOC_CTX *t)
93 /* disabled enrole/disenrole until we have __thread support */
94 MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
95 DLIST_ADD(list_head, t);
96 MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
101 static void talloc_disenroll(TALLOC_CTX *t)
104 /* disabled enrole/disenrole until we have __thread support */
105 MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
106 DLIST_REMOVE(list_head, t);
107 MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
112 /** Create a new talloc context. **/
113 static TALLOC_CTX *talloc_init_internal(void)
117 t = (TALLOC_CTX *)malloc(sizeof(TALLOC_CTX));
120 t->total_alloc_size = 0;
131 * Create a new talloc context, with a name specifying its purpose.
134 TALLOC_CTX *talloc_init(char const *fmt, ...)
139 t = talloc_init_internal();
142 * t->name must not be talloced.
143 * as destroying the pool would destroy it. JRA.
147 vasprintf(&t->name, fmt, ap);
159 /** Allocate a bit of memory from the specified pool **/
160 void *talloc(TALLOC_CTX *t, size_t size)
163 struct talloc_chunk *tc;
165 if (!t || size == 0) return NULL;
169 tc = malloc(sizeof(*tc));
175 t->total_alloc_size += size;
184 /** A talloc version of realloc */
185 void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
187 struct talloc_chunk *tc;
190 /* size zero is equivalent to free() */
194 /* realloc(NULL) is equavalent to malloc() */
196 return talloc(t, size);
198 for (tc=t->list; tc; tc=tc->next) {
199 if (tc->ptr == ptr) {
200 new_ptr = Realloc(ptr, size);
202 t->total_alloc_size += (size - tc->size);
212 /** Destroy all the memory allocated inside @p t, but not @p t
214 void talloc_destroy_pool(TALLOC_CTX *t)
216 struct talloc_chunk *c;
223 SAFE_FREE(t->list->ptr);
228 t->total_alloc_size = 0;
231 /** Destroy a whole pool including the context */
232 void talloc_destroy(TALLOC_CTX *t)
237 talloc_destroy_pool(t);
243 /** Return the current total size of the pool. */
244 size_t talloc_pool_size(TALLOC_CTX *t)
246 return t->total_alloc_size;
249 const char *talloc_pool_name(TALLOC_CTX const *t)
251 if (t) return t->name;
257 /** talloc and zero memory. */
258 void *talloc_zero(TALLOC_CTX *t, size_t size)
260 void *p = talloc(t, size);
263 memset(p, '\0', size);
270 /** memdup with a talloc. */
271 void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
273 void *newp = talloc(t,size);
276 memcpy(newp, p, size);
282 /** strdup with a talloc */
283 char *talloc_strdup(TALLOC_CTX *t, const char *p)
285 return talloc_memdup(t, p, strlen(p) + 1);
288 /** strndup with a talloc */
289 char *talloc_strndup(TALLOC_CTX *t, const char *p, size_t n)
291 size_t len = strnlen(p, n);
294 ret = talloc(t, len + 1);
295 if (!ret) { return NULL; }
301 /** strdup_w with a talloc */
302 smb_ucs2_t *talloc_strdup_w(TALLOC_CTX *t, const smb_ucs2_t *p)
305 return talloc_memdup(t, p, (strlen_w(p) + 1) * sizeof(smb_ucs2_t));
310 * Perform string formatting, and return a pointer to newly allocated
311 * memory holding the result, inside a memory pool.
313 char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
319 ret = talloc_vasprintf(t, fmt, ap);
325 char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
333 len = vsnprintf(NULL, 0, fmt, ap2);
335 ret = talloc(t, len+1);
338 vsnprintf(ret, len+1, fmt, ap2);
346 * Realloc @p s to append the formatted result of @p fmt and return @p
347 * s, which may have moved. Good for gradually accumulating output
348 * into a string buffer.
350 char *talloc_asprintf_append(TALLOC_CTX *t, char *s,
351 const char *fmt, ...)
356 s = talloc_vasprintf_append(t, s, fmt, ap);
364 * Realloc @p s to append the formatted result of @p fmt and @p ap,
365 * and return @p s, which may have moved. Good for gradually
366 * accumulating output into a string buffer.
368 char *talloc_vasprintf_append(TALLOC_CTX *t, char *s,
369 const char *fmt, va_list ap)
377 len = vsnprintf(NULL, 0, fmt, ap2);
379 s = talloc_realloc(t, s, s_len + len+1);
384 vsnprintf(s+s_len, len+1, fmt, ap2);
391 * Return a human-readable description of all talloc memory usage.
392 * The result is allocated from @p t.
394 char *talloc_describe_all(TALLOC_CTX *rt)
396 int n_pools = 0, total_chunks = 0;
397 size_t total_bytes = 0;
401 if (!rt) return NULL;
403 s = talloc_asprintf(rt, "global talloc allocations in pid: %u\n",
404 (unsigned) getpid());
405 s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
406 "name", "chunks", "bytes");
407 s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
408 "----------------------------------------",
411 MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
413 for (it = list_head; it; it = it->next) {
420 talloc_get_allocation(it, &bytes, &n_chunks);
423 fstrcpy(what, it->name);
425 slprintf(what, sizeof(what), "@%p", it);
427 s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
431 total_bytes += bytes;
432 total_chunks += n_chunks;
435 MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
437 s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
438 "----------------------------------------",
442 s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
444 (unsigned) total_chunks, (unsigned) total_bytes);
452 * Return an estimated memory usage for the specified pool. This does
453 * not include memory used by the underlying malloc implementation.
455 void talloc_get_allocation(TALLOC_CTX *t,
459 struct talloc_chunk *chunk;
465 for (chunk = t->list; chunk; chunk = chunk->next) {
467 *total_bytes += chunk->size;
474 move a lump of memory from one talloc context to another
475 return the ptr on success, or NULL if it could not be found
476 in the old context or could not be transferred
478 const void *talloc_steal(TALLOC_CTX *old_ctx, TALLOC_CTX *new_ctx, const void *ptr)
480 struct talloc_chunk *tc, *tc2;
482 if (!ptr || !old_ctx->list) return NULL;
484 /* as a special case, see if its the first element in the
486 if (old_ctx->list->ptr == ptr) {
488 old_ctx->list = old_ctx->list->next;
489 tc->next = new_ctx->list;
491 old_ctx->total_alloc_size -= tc->size;
492 new_ctx->total_alloc_size += tc->size;
496 /* find it in the old context */
497 for (tc=old_ctx->list; tc->next; tc=tc->next) {
498 if (tc->next->ptr == ptr) break;
501 if (!tc->next) return NULL;
503 /* move it to the new context */
505 tc->next = tc->next->next;
506 tc2->next = new_ctx->list;
508 old_ctx->total_alloc_size -= tc2->size;
509 new_ctx->total_alloc_size += tc2->size;