5fffe58f9f9bd5b6c7bab416b6f75e8b1ddfdbda
[bbaumbach/samba-autobuild/.git] / source3 / 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         size_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_ctx;
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 = NULL;
86
87
88 /**
89  * Add to the global list
90  **/
91 static void talloc_enroll(TALLOC_CTX *t)
92 {
93         t->next_ctx = list_head;
94         list_head = t;
95 }
96
97
98 static void talloc_disenroll(TALLOC_CTX *t)
99 {
100         TALLOC_CTX **ttmp;
101
102         /* Use a double-* so that no special case is required for the
103          * list head. */
104         for (ttmp = &list_head; *ttmp; ttmp = &((*ttmp)->next_ctx))
105                 if (*ttmp == t) {
106                         /* ttmp is the link that points to t, either
107                          * list_head or the next_ctx link in its
108                          * predecessor */
109                         *ttmp = t->next_ctx;
110                         t->next_ctx = NULL;     /* clobber */
111                         return;
112                 }
113         abort();                /* oops, this talloc was already
114                                  * clobbered or something else went
115                                  * wrong. */
116 }
117
118
119 /** Create a new talloc context. **/
120 TALLOC_CTX *talloc_init(void)
121 {
122         TALLOC_CTX *t;
123
124         t = (TALLOC_CTX *)malloc(sizeof(TALLOC_CTX));
125         if (t) {
126                 t->list = NULL;
127                 t->total_alloc_size = 0;
128                 t->name = NULL;
129                 talloc_enroll(t);
130         }
131
132         return t;
133 }
134
135
136
137 /**
138  * Create a new talloc context, with a name specifying its purpose.
139  * Please call this in preference to talloc_init().
140  **/
141
142  TALLOC_CTX *talloc_init_named(char const *fmt, ...) 
143 {
144         TALLOC_CTX *t;
145         va_list ap;
146
147         t = talloc_init();
148         if (t && fmt) {
149                 /*
150                  * t->name must not be talloced.
151                  * as destroying the pool would destroy it. JRA.
152                  */
153                 t->name = NULL;
154                 va_start(ap, fmt);
155                 vasprintf(&t->name, fmt, ap);
156                 va_end(ap);
157                 if (!t->name) {
158                         talloc_destroy(t);
159                         t = NULL;
160                 }
161         }
162         
163         return t;
164 }
165
166
167 /** Allocate a bit of memory from the specified pool **/
168 void *talloc(TALLOC_CTX *t, size_t size)
169 {
170         void *p;
171         struct talloc_chunk *tc;
172
173         if (!t || size == 0) return NULL;
174
175         p = malloc(size);
176         if (p) {
177                 tc = malloc(sizeof(*tc));
178                 if (tc) {
179                         tc->ptr = p;
180                         tc->size = size;
181                         tc->next = t->list;
182                         t->list = tc;
183                         t->total_alloc_size += size;
184                 }
185                 else {
186                         SAFE_FREE(p);
187                 }
188         }
189         return p;
190 }
191
192 /** A talloc version of realloc */
193 void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
194 {
195         struct talloc_chunk *tc;
196         void *new_ptr;
197
198         /* size zero is equivalent to free() */
199         if (!t || size == 0)
200                 return NULL;
201
202         /* realloc(NULL) is equavalent to malloc() */
203         if (ptr == NULL)
204                 return talloc(t, size);
205
206         for (tc=t->list; tc; tc=tc->next) {
207                 if (tc->ptr == ptr) {
208                         new_ptr = Realloc(ptr, size);
209                         if (new_ptr) {
210                                 t->total_alloc_size += (size - tc->size);
211                                 tc->size = size;
212                                 tc->ptr = new_ptr;
213                         }
214                         return new_ptr;
215                 }
216         }
217         return NULL;
218 }
219
220 /** Destroy all the memory allocated inside @p t, but not @p t
221  * itself. */
222 void talloc_destroy_pool(TALLOC_CTX *t)
223 {
224         struct talloc_chunk *c;
225         
226         if (!t)
227                 return;
228
229         while (t->list) {
230                 c = t->list->next;
231                 SAFE_FREE(t->list->ptr);
232                 SAFE_FREE(t->list);
233                 t->list = c;
234         }
235
236         t->total_alloc_size = 0;
237 }
238
239 /** Destroy a whole pool including the context */
240 void talloc_destroy(TALLOC_CTX *t)
241 {
242         if (!t)
243                 return;
244
245         talloc_destroy_pool(t);
246         talloc_disenroll(t);
247         SAFE_FREE(t->name);
248         memset(t, 0, sizeof(TALLOC_CTX));
249         SAFE_FREE(t);
250 }
251
252 /** Return the current total size of the pool. */
253 size_t talloc_pool_size(TALLOC_CTX *t)
254 {
255         if (t)
256                 return t->total_alloc_size;
257         else
258                 return 0;
259 }
260
261 const char * talloc_pool_name(TALLOC_CTX const *t)
262 {
263         if (t)
264                 return t->name;
265         else
266                 return NULL;
267 }
268
269
270 /** talloc and zero memory. */
271 void *talloc_zero(TALLOC_CTX *t, size_t size)
272 {
273         void *p = talloc(t, size);
274
275         if (p)
276                 memset(p, '\0', size);
277
278         return p;
279 }
280
281 /** memdup with a talloc. */
282 void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
283 {
284         void *newp = talloc(t,size);
285
286         if (newp)
287                 memcpy(newp, p, size);
288
289         return newp;
290 }
291
292 /** strdup with a talloc */
293 char *talloc_strdup(TALLOC_CTX *t, const char *p)
294 {
295         if (p)
296                 return talloc_memdup(t, p, strlen(p) + 1);
297         else
298                 return NULL;
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         else
307                 return NULL;
308 }
309
310 /**
311  * Perform string formatting, and return a pointer to newly allocated
312  * memory holding the result, inside a memory pool.
313  **/
314  char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
315 {
316         va_list ap;
317         char *ret;
318
319         va_start(ap, fmt);
320         ret = talloc_vasprintf(t, fmt, ap);
321         va_end(ap);
322         return ret;
323 }
324
325
326  char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
327 {       
328         int len;
329         char *ret;
330         va_list ap2;
331         
332         VA_COPY(ap2, ap);
333
334         len = vsnprintf(NULL, 0, fmt, ap2);
335
336         ret = talloc(t, len+1);
337         if (ret) {
338                 VA_COPY(ap2, ap);
339                 vsnprintf(ret, len+1, fmt, ap2);
340         }
341
342         return ret;
343 }
344
345
346 /**
347  * Realloc @p s to append the formatted result of @p fmt and return @p
348  * s, which may have moved.  Good for gradually accumulating output
349  * into a string buffer.
350  **/
351  char *talloc_asprintf_append(TALLOC_CTX *t, char *s,
352                               const char *fmt, ...)
353 {
354         va_list ap;
355
356         va_start(ap, fmt);
357         s = talloc_vasprintf_append(t, s, fmt, ap);
358         va_end(ap);
359         return s;
360 }
361
362
363
364 /**
365  * Realloc @p s to append the formatted result of @p fmt and @p ap,
366  * and return @p s, which may have moved.  Good for gradually
367  * accumulating output into a string buffer.
368  **/
369  char *talloc_vasprintf_append(TALLOC_CTX *t, char *s,
370                                const char *fmt, va_list ap)
371 {       
372         int len, s_len;
373         va_list ap2;
374
375         VA_COPY(ap2, ap);
376
377         s_len = strlen(s);
378         len = vsnprintf(NULL, 0, fmt, ap2);
379
380         s = talloc_realloc(t, s, s_len + len+1);
381         if (!s) return NULL;
382
383         VA_COPY(ap2, ap);
384
385         vsnprintf(s+s_len, len+1, fmt, ap2);
386
387         return s;
388 }
389
390
391 /**
392  * Return a human-readable description of all talloc memory usage.
393  * The result is allocated from @p t.
394  **/
395 char *talloc_describe_all(TALLOC_CTX *rt)
396 {
397         int n_pools = 0, total_chunks = 0;
398         size_t total_bytes = 0;
399         TALLOC_CTX *it;
400         char *s;
401
402         if (!rt) return NULL;
403
404         s = talloc_asprintf(rt, "global talloc allocations in pid: %u\n",
405                             (unsigned) sys_getpid());
406         s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
407                                    "name", "chunks", "bytes");
408         s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
409                                    "----------------------------------------",
410                                    "--------",
411                                    "--------"); 
412         
413         for (it = list_head; it; it = it->next_ctx) {
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         s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
436                                    "----------------------------------------",
437                                    "--------",
438                                    "--------"); 
439
440         s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
441                                    "TOTAL",
442                                    (unsigned) total_chunks, (unsigned) total_bytes);
443
444         return s;
445 }
446
447
448
449 /**
450  * Return an estimated memory usage for the specified pool.  This does
451  * not include memory used by the underlying malloc implementation.
452  **/
453 void talloc_get_allocation(TALLOC_CTX *t,
454                            size_t *total_bytes,
455                            int *n_chunks)
456 {
457         struct talloc_chunk *chunk;
458
459         if (t) {
460                 *total_bytes = 0;
461                 *n_chunks = 0;
462
463                 for (chunk = t->list; chunk; chunk = chunk->next) {
464                         n_chunks[0]++;
465                         *total_bytes += chunk->size;
466                 }
467         }
468 }
469
470
471 /** @} */