From 0af2efcdc4cd669db2a2ee582674dc030c6371a9 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 8 Jan 2008 22:42:27 +0100 Subject: Don't shrink a talloc area if we have less than 1k to gain (This used to be commit 28a72ebd4541fb54f284da49081345e54130c75a) --- source3/lib/talloc/talloc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 4d72c0e871..6dbe21bbf1 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -787,6 +787,11 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n tc = talloc_chunk_from_ptr(ptr); + if ((size < tc->size) && ((tc->size - size) < 1024)) { + tc->size = size; + return ptr; + } + /* don't allow realloc on referenced pointers */ if (unlikely(tc->refs)) { return NULL; -- cgit From ebb21268df233933938e64e83ed315313aedd544 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 9 Jan 2008 01:34:21 +0100 Subject: Fix talloctort: move size check after referenced ptr check. Michael (This used to be commit 45b219642c529865a898625eeb0433c60b233867) --- source3/lib/talloc/talloc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 6dbe21bbf1..476d765104 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -787,16 +787,16 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n tc = talloc_chunk_from_ptr(ptr); - if ((size < tc->size) && ((tc->size - size) < 1024)) { - tc->size = size; - return ptr; - } - /* don't allow realloc on referenced pointers */ if (unlikely(tc->refs)) { return NULL; } + if ((size < tc->size) && ((tc->size - size) < 1024)) { + tc->size = size; + return ptr; + } + /* by resetting magic we catch users of the old memory */ tc->flags |= TALLOC_FLAG_FREE; -- cgit From 2e3ac4d3fe65ee72111c03a9b6fabf06f8192a69 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 9 Jan 2008 01:35:43 +0100 Subject: Add a comment. Michael (This used to be commit 3a4bf4b7c3081048f0d5491dae6610388c268c2f) --- source3/lib/talloc/talloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 476d765104..3e976bc0fc 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -792,6 +792,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n return NULL; } + /* don't shrink if we have less than 1k to gain */ if ((size < tc->size) && ((tc->size - size) < 1024)) { tc->size = size; return ptr; -- cgit From 1ed4fcb271b7885c274bd88bafed8116779d8eb6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 5 Jan 2008 18:26:54 +0100 Subject: Implement talloc_pool() A talloc pool is a chunk of memory that can be used as a context for further talloc calls. Allocations with the pool as the parent just chew from that memory by incrementing a pointer. If the talloc pool is full, then we fall back to the normal system-level malloc(3) to get memory. The use case for talloc pools is the transient memory that is used for handling a single SMB request. Incrementing a pointer will be way faster than any malloc implementation. There is a downside of this: If you use talloc_steal() to move something out of the pool, the whole pool memory is kept around until the last object inside the pool is freed. So if you talloc_free() the pool, it might happen that the memory is freed later. So don't hang anything off a talloc pool that should live long. Volker (This used to be commit 287e29d988813007eeebc0c2bef3b46ab8bedee9) --- source3/lib/talloc/talloc.c | 176 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 7 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 3e976bc0fc..178bbb97e4 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -60,6 +60,8 @@ #define TALLOC_MAGIC 0xe814ec70 #define TALLOC_FLAG_FREE 0x01 #define TALLOC_FLAG_LOOP 0x02 +#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ +#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ #define TALLOC_MAGIC_REFERENCE ((const char *)1) /* by default we abort when given a bad pointer (such as when talloc_free() is called @@ -109,6 +111,19 @@ struct talloc_chunk { const char *name; size_t size; unsigned flags; + + /* + * "pool" has dual use: + * + * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" + * marks the end of the currently allocated area. + * + * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" + * is a pointer to the struct talloc_chunk of the pool that it was + * allocated from. This way children can quickly find the pool to chew + * from. + */ + void *pool; }; /* 16 byte alignment seems to keep everyone happy */ @@ -200,12 +215,82 @@ const char *talloc_parent_name(const void *ptr) return tc? tc->name : NULL; } +/* + A pool carries an in-pool object count count in the first 16 bytes. + bytes. This is done to support talloc_steal() to a parent outside of the + pool. The count includes the pool itself, so a talloc_free() on a pool will + only destroy the pool if the count has dropped to zero. A talloc_free() of a + pool member will reduce the count, and eventually also call free(3) on the + pool memory. + + The object count is not put into "struct talloc_chunk" because it is only + relevant for talloc pools and the alignment to 16 bytes would increase the + memory footprint of each talloc chunk by those 16 bytes. +*/ + +#define TALLOC_POOL_HDR_SIZE 16 + +static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc) +{ + return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk)); +} + +/* + Allocate from a pool +*/ + +static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, + size_t size) +{ + struct talloc_chunk *pool_ctx = NULL; + size_t space_left; + struct talloc_chunk *result; + + if (parent == NULL) { + return NULL; + } + + if (parent->flags & TALLOC_FLAG_POOL) { + pool_ctx = parent; + } + else if (parent->flags & TALLOC_FLAG_POOLMEM) { + pool_ctx = (struct talloc_chunk *)parent->pool; + } + + if (pool_ctx == NULL) { + return NULL; + } + + space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size) + - ((char *)pool_ctx->pool); + + /* + * Align size to 16 bytes + */ + size = ((size + 15) & ~15); + + if (space_left < size) { + return NULL; + } + + result = (struct talloc_chunk *)pool_ctx->pool; + + pool_ctx->pool = (void *)((char *)result + size); + + result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; + result->pool = pool_ctx; + + *talloc_pool_objectcount(pool_ctx) += 1; + + return result; +} + /* Allocate a bit of memory as a child of an existing pointer */ static inline void *__talloc(const void *context, size_t size) { - struct talloc_chunk *tc; + struct talloc_chunk *tc = NULL; if (unlikely(context == NULL)) { context = null_context; @@ -215,11 +300,19 @@ static inline void *__talloc(const void *context, size_t size) return NULL; } - tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); - if (unlikely(tc == NULL)) return NULL; + if (context != NULL) { + tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), + TC_HDR_SIZE+size); + } + + if (tc == NULL) { + tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); + if (unlikely(tc == NULL)) return NULL; + tc->flags = TALLOC_MAGIC; + tc->pool = NULL; + } tc->size = size; - tc->flags = TALLOC_MAGIC; tc->destructor = NULL; tc->child = NULL; tc->name = NULL; @@ -245,6 +338,29 @@ static inline void *__talloc(const void *context, size_t size) return TC_PTR_FROM_CHUNK(tc); } +/* + * Create a talloc pool + */ + +void *talloc_pool(const void *context, size_t size) +{ + void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE); + struct talloc_chunk *tc; + + if (unlikely(result == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(result); + + tc->flags |= TALLOC_FLAG_POOL; + tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE; + + *talloc_pool_objectcount(tc) = 1; + + return result; +} + /* setup a destructor to be called on free of a pointer the destructor should return 0 on success, or -1 on failure. @@ -420,7 +536,29 @@ static inline int _talloc_free(void *ptr) } tc->flags |= TALLOC_FLAG_FREE; - free(tc); + + if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) { + struct talloc_chunk *pool; + unsigned int *pool_object_count; + + pool = (tc->flags & TALLOC_FLAG_POOL) + ? tc : (struct talloc_chunk *)tc->pool; + + pool_object_count = talloc_pool_objectcount(pool); + + if (*pool_object_count == 0) { + TALLOC_ABORT("Pool object count zero!"); + } + + *pool_object_count -= 1; + + if (*pool_object_count == 0) { + free(pool); + } + } + else { + free(tc); + } return 0; } @@ -718,6 +856,10 @@ void talloc_free_children(void *ptr) talloc_steal(new_parent, child); } } + + if (tc->flags & TALLOC_FLAG_POOL) { + tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); + } } /* @@ -769,6 +911,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n { struct talloc_chunk *tc; void *new_ptr; + bool malloced = false; /* size zero is equivalent to free() */ if (unlikely(size == 0)) { @@ -808,7 +951,23 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n free(tc); } #else - new_ptr = realloc(tc, size + TC_HDR_SIZE); + if (tc->flags & TALLOC_FLAG_POOLMEM) { + + new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); + *talloc_pool_objectcount(tc->pool) -= 1; + + if (new_ptr == NULL) { + new_ptr = malloc(TC_HDR_SIZE+size); + malloced = true; + } + + if (new_ptr) { + memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE); + } + } + else { + new_ptr = realloc(tc, size + TC_HDR_SIZE); + } #endif if (unlikely(!new_ptr)) { tc->flags &= ~TALLOC_FLAG_FREE; @@ -816,7 +975,10 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n } tc = (struct talloc_chunk *)new_ptr; - tc->flags &= ~TALLOC_FLAG_FREE; + tc->flags &= ~TALLOC_FLAG_FREE; + if (malloced) { + tc->flags &= ~TALLOC_FLAG_POOLMEM; + } if (tc->parent) { tc->parent->child = tc; } -- cgit From 4803cc5d3ce7db872bd21f6a1232f7cabc46186e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 10 Jan 2008 11:34:07 +0100 Subject: Mark talloc_pool memory for valgrind (This used to be commit d89e42f1d2faa018c584025296d6be8195cbcf20) --- source3/lib/talloc/talloc.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 178bbb97e4..ea4480286e 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -245,6 +245,7 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, struct talloc_chunk *pool_ctx = NULL; size_t space_left; struct talloc_chunk *result; + size_t chunk_size; if (parent == NULL) { return NULL; @@ -267,15 +268,19 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, /* * Align size to 16 bytes */ - size = ((size + 15) & ~15); + chunk_size = ((size + 15) & ~15); - if (space_left < size) { + if (space_left < chunk_size) { return NULL; } result = (struct talloc_chunk *)pool_ctx->pool; - pool_ctx->pool = (void *)((char *)result + size); +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(result, size); +#endif + + pool_ctx->pool = (void *)((char *)result + chunk_size); result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; result->pool = pool_ctx; @@ -358,6 +363,10 @@ void *talloc_pool(const void *context, size_t size) *talloc_pool_objectcount(tc) = 1; +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size); +#endif + return result; } @@ -859,6 +868,10 @@ void talloc_free_children(void *ptr) if (tc->flags & TALLOC_FLAG_POOL) { tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS( + tc->pool, tc->size - TALLOC_POOL_HDR_SIZE); +#endif } } -- cgit From 97a50593fe86456a72762ba4a768614de23c3f14 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 10 Jan 2008 11:35:17 +0100 Subject: talloc_free_children can only reset pool if it's empty (This used to be commit 0272b46515b4c4515d5cad8e86fab61d8e91e29e) --- source3/lib/talloc/talloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index ea4480286e..8683e361a6 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -866,7 +866,8 @@ void talloc_free_children(void *ptr) } } - if (tc->flags & TALLOC_FLAG_POOL) { + if ((tc->flags & TALLOC_FLAG_POOL) + && (*talloc_pool_objectcount(tc) == 1)) { tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) VALGRIND_MAKE_MEM_NOACCESS( -- cgit From 138954e70e18e53f1ae81bad4641380bc8ab3bd3 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 10 Jan 2008 11:35:40 +0100 Subject: Fix a c++ warning (This used to be commit ee905a085fff5410d02c3e5fa2664e989de4afd4) --- source3/lib/talloc/talloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 8683e361a6..9dcd8a2a83 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -968,7 +968,8 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n if (tc->flags & TALLOC_FLAG_POOLMEM) { new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); - *talloc_pool_objectcount(tc->pool) -= 1; + *talloc_pool_objectcount((struct talloc_chunk *) + (tc->pool)) -= 1; if (new_ptr == NULL) { new_ptr = malloc(TC_HDR_SIZE+size); -- cgit