first public release of samba4 code
[samba.git] / source / lib / talloc.c
1 /* 
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>
6    
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.
11    
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /**
23    @defgroup talloc Simple memory allocator
24    @{
25    
26    This is a very simple temporary memory allocator. To use it do the following:
27
28    1) when you first want to allocate a pool of meomry use
29    talloc_init() and save the resulting context pointer somewhere
30
31    2) to allocate memory use talloc()
32
33    3) when _all_ of the memory allocated using this context is no longer needed
34    use talloc_destroy()
35
36    talloc does not zero the memory. It guarantees memory of a
37    TALLOC_ALIGN alignment
38
39    @sa talloc.h
40 */
41
42 /**
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.
46  *
47  * That smells like a premature optimization, though.  -- mbp
48  **/
49
50 /**
51  * If you want testing for memory corruption, link with dmalloc or use
52  * Insure++.  It doesn't seem useful to duplicate them here.
53  **/
54
55 #include "includes.h"
56
57 struct talloc_chunk {
58         struct talloc_chunk *next;
59         size_t size;
60         void *ptr;
61 };
62
63
64 struct talloc_ctx {
65         struct talloc_chunk *list;
66         off_t total_alloc_size;
67
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. **/
71         char *name;
72
73         /** Pointer to the next allocate talloc pool, so that we can
74          * summarize all talloc memory usage. **/
75         struct talloc_ctx *next, *prev;
76 };
77
78
79 /**
80  * Start of linked list of all talloc pools.
81  *
82  * @todo We should turn the global list off when using Insure++,
83  * otherwise all the memory will be seen as still reachable.
84  **/
85 static TALLOC_CTX *list_head;
86
87 /**
88  * Add to the global list
89  **/
90 static void talloc_enroll(TALLOC_CTX *t)
91 {
92 #if 0
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);
97 #endif
98 }
99
100
101 static void talloc_disenroll(TALLOC_CTX *t)
102 {
103 #if 0
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);
108 #endif
109 }
110
111
112 /** Create a new talloc context. **/
113 static TALLOC_CTX *talloc_init_internal(void)
114 {
115         TALLOC_CTX *t;
116
117         t = (TALLOC_CTX *)malloc(sizeof(TALLOC_CTX));
118         if (t) {
119                 t->list = NULL;
120                 t->total_alloc_size = 0;
121                 t->name = NULL;
122                 talloc_enroll(t);
123         }
124
125         return t;
126 }
127
128
129
130 /**
131  * Create a new talloc context, with a name specifying its purpose.
132  **/
133
134  TALLOC_CTX *talloc_init(char const *fmt, ...) 
135 {
136         TALLOC_CTX *t;
137         va_list ap;
138
139         t = talloc_init_internal();
140         if (t && fmt) {
141                 /*
142                  * t->name must not be talloced.
143                  * as destroying the pool would destroy it. JRA.
144                  */
145                 t->name = NULL;
146                 va_start(ap, fmt);
147                 vasprintf(&t->name, fmt, ap);
148                 va_end(ap);
149                 if (!t->name) {
150                         talloc_destroy(t);
151                         t = NULL;
152                 }
153         }
154         
155         return t;
156 }
157
158
159 /** Allocate a bit of memory from the specified pool **/
160 void *talloc(TALLOC_CTX *t, size_t size)
161 {
162         void *p;
163         struct talloc_chunk *tc;
164
165         if (!t || size == 0) return NULL;
166
167         p = malloc(size);
168         if (p) {
169                 tc = malloc(sizeof(*tc));
170                 if (tc) {
171                         tc->ptr = p;
172                         tc->size = size;
173                         tc->next = t->list;
174                         t->list = tc;
175                         t->total_alloc_size += size;
176                 }
177                 else {
178                         SAFE_FREE(p);
179                 }
180         }
181         return p;
182 }
183
184 /** A talloc version of realloc */
185 void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
186 {
187         struct talloc_chunk *tc;
188         void *new_ptr;
189
190         /* size zero is equivalent to free() */
191         if (!t || size == 0)
192                 return NULL;
193
194         /* realloc(NULL) is equavalent to malloc() */
195         if (ptr == NULL)
196                 return talloc(t, size);
197
198         for (tc=t->list; tc; tc=tc->next) {
199                 if (tc->ptr == ptr) {
200                         new_ptr = Realloc(ptr, size);
201                         if (new_ptr) {
202                                 t->total_alloc_size += (size - tc->size);
203                                 tc->size = size;
204                                 tc->ptr = new_ptr;
205                         }
206                         return new_ptr;
207                 }
208         }
209         return NULL;
210 }
211
212 /** Destroy all the memory allocated inside @p t, but not @p t
213  * itself. */
214 void talloc_destroy_pool(TALLOC_CTX *t)
215 {
216         struct talloc_chunk *c;
217         
218         if (!t)
219                 return;
220
221         while (t->list) {
222                 c = t->list->next;
223                 SAFE_FREE(t->list->ptr);
224                 SAFE_FREE(t->list);
225                 t->list = c;
226         }
227
228         t->total_alloc_size = 0;
229 }
230
231 /** Destroy a whole pool including the context */
232 void talloc_destroy(TALLOC_CTX *t)
233 {
234         if (!t)
235                 return;
236
237         talloc_destroy_pool(t);
238         talloc_disenroll(t);
239         SAFE_FREE(t->name);
240         SAFE_FREE(t);
241 }
242
243 /** Return the current total size of the pool. */
244 size_t talloc_pool_size(TALLOC_CTX *t)
245 {
246         return t->total_alloc_size;
247 }
248
249 const char *talloc_pool_name(TALLOC_CTX const *t)
250 {
251         if (t) return t->name;
252
253         return NULL;
254 }
255
256
257 /** talloc and zero memory. */
258 void *talloc_zero(TALLOC_CTX *t, size_t size)
259 {
260         void *p = talloc(t, size);
261
262         if (p) {
263                 memset(p, '\0', size);
264         }
265
266         return p;
267 }
268
269
270 /** memdup with a talloc. */
271 void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
272 {
273         void *newp = talloc(t,size);
274
275         if (newp) {
276                 memcpy(newp, p, size);
277         }
278
279         return newp;
280 }
281
282 /** strdup with a talloc */
283 char *talloc_strdup(TALLOC_CTX *t, const char *p)
284 {
285         return talloc_memdup(t, p, strlen(p) + 1);
286 }
287
288 /** strndup with a talloc */
289 char *talloc_strndup(TALLOC_CTX *t, const char *p, size_t n)
290 {
291         size_t len = strnlen(p, n);
292         char *ret;
293
294         ret = talloc(t, len + 1);
295         if (!ret) { return NULL; }
296         memcpy(ret, p, len);
297         ret[len] = 0;
298         return ret;
299 }
300
301 /** strdup_w with a talloc */
302 smb_ucs2_t *talloc_strdup_w(TALLOC_CTX *t, const smb_ucs2_t *p)
303 {
304         if (p)
305                 return talloc_memdup(t, p, (strlen_w(p) + 1) * sizeof(smb_ucs2_t));
306         return NULL;
307 }
308
309 /**
310  * Perform string formatting, and return a pointer to newly allocated
311  * memory holding the result, inside a memory pool.
312  **/
313  char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
314 {
315         va_list ap;
316         char *ret;
317
318         va_start(ap, fmt);
319         ret = talloc_vasprintf(t, fmt, ap);
320         va_end(ap);
321         return ret;
322 }
323
324
325  char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
326 {       
327         int len;
328         char *ret;
329         va_list ap2;
330         
331         VA_COPY(ap2, ap);
332
333         len = vsnprintf(NULL, 0, fmt, ap2);
334
335         ret = talloc(t, len+1);
336         if (ret) {
337                 VA_COPY(ap2, ap);
338                 vsnprintf(ret, len+1, fmt, ap2);
339         }
340
341         return ret;
342 }
343
344
345 /**
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.
349  **/
350  char *talloc_asprintf_append(TALLOC_CTX *t, char *s,
351                               const char *fmt, ...)
352 {
353         va_list ap;
354
355         va_start(ap, fmt);
356         s = talloc_vasprintf_append(t, s, fmt, ap);
357         va_end(ap);
358         return s;
359 }
360
361
362
363 /**
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.
367  **/
368  char *talloc_vasprintf_append(TALLOC_CTX *t, char *s,
369                                const char *fmt, va_list ap)
370 {       
371         int len, s_len;
372         va_list ap2;
373
374         VA_COPY(ap2, ap);
375
376         s_len = strlen(s);
377         len = vsnprintf(NULL, 0, fmt, ap2);
378
379         s = talloc_realloc(t, s, s_len + len+1);
380         if (!s) return NULL;
381
382         VA_COPY(ap2, ap);
383
384         vsnprintf(s+s_len, len+1, fmt, ap2);
385
386         return s;
387 }
388
389
390 /**
391  * Return a human-readable description of all talloc memory usage.
392  * The result is allocated from @p t.
393  **/
394 char *talloc_describe_all(TALLOC_CTX *rt)
395 {
396         int n_pools = 0, total_chunks = 0;
397         size_t total_bytes = 0;
398         TALLOC_CTX *it;
399         char *s;
400
401         if (!rt) return NULL;
402
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                                    "----------------------------------------",
409                                    "--------",
410                                    "--------"); 
411         MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
412         
413         for (it = list_head; it; it = it->next) {
414                 size_t bytes;
415                 int n_chunks;
416                 fstring what;
417                 
418                 n_pools++;
419                 
420                 talloc_get_allocation(it, &bytes, &n_chunks);
421
422                 if (it->name)
423                         fstrcpy(what, it->name);
424                 else
425                         slprintf(what, sizeof(what), "@%p", it);
426                 
427                 s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
428                                            what,
429                                            (unsigned) n_chunks,
430                                            (unsigned) bytes);
431                 total_bytes += bytes;
432                 total_chunks += n_chunks;
433         }
434
435         MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
436
437         s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
438                                    "----------------------------------------",
439                                    "--------",
440                                    "--------"); 
441
442         s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
443                                    "TOTAL",
444                                    (unsigned) total_chunks, (unsigned) total_bytes);
445
446         return s;
447 }
448
449
450
451 /**
452  * Return an estimated memory usage for the specified pool.  This does
453  * not include memory used by the underlying malloc implementation.
454  **/
455 void talloc_get_allocation(TALLOC_CTX *t,
456                            size_t *total_bytes,
457                            int *n_chunks)
458 {
459         struct talloc_chunk *chunk;
460
461         if (t) {
462                 *total_bytes = 0;
463                 *n_chunks = 0;
464
465                 for (chunk = t->list; chunk; chunk = chunk->next) {
466                         n_chunks[0]++;
467                         *total_bytes += chunk->size;
468                 }
469         }
470 }
471
472
473 /* 
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
477 */
478 const void *talloc_steal(TALLOC_CTX *old_ctx, TALLOC_CTX *new_ctx, const void *ptr)
479 {
480         struct talloc_chunk *tc, *tc2;
481
482         if (!ptr || !old_ctx->list) return NULL;
483
484         /* as a special case, see if its the first element in the
485            list */
486         if (old_ctx->list->ptr == ptr) {
487                 tc = old_ctx->list;
488                 old_ctx->list = old_ctx->list->next;
489                 tc->next = new_ctx->list;
490                 new_ctx->list = tc;
491                 old_ctx->total_alloc_size -= tc->size;
492                 new_ctx->total_alloc_size += tc->size;
493                 return ptr;
494         }
495
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;
499         }
500
501         if (!tc->next) return NULL;
502
503         /* move it to the new context */
504         tc2 = tc->next;
505         tc->next = tc->next->next;
506         tc2->next = new_ctx->list;
507         new_ctx->list = tc2;
508         old_ctx->total_alloc_size -= tc2->size;
509         new_ctx->total_alloc_size += tc2->size;
510         
511         return ptr;
512 }
513
514
515 /** @} */