From 6d9c357ff64e799dfeacda6a176012de10c7f5c1 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 23 Aug 2011 21:04:02 +0200 Subject: [PATCH] btr: Introduce btr_add_output_dont_free(). At the moment, all buffers which are fed to a buffer tree must be allocated on the heap since the buffer tree code automatically frees the buffer once its refcount dropped to zero. The new afh receiver, however, mmaps the audio file and likes to feed chunks of this memory map into the buffer tree. This is currently impossible because such buffers must not be freed. This patch adds the new public function btr_add_output_dont_free() which works like btr_add_output() but sets the new dont_free bit which prevents the buffer from being deallocated. Also btr_inplace_ok() is changed to return "false" whenever there exists a buffer in the input queue with the dont_free bit set. --- buffer_tree.c | 44 ++++++++++++++++++++++++++++++++++++++++---- buffer_tree.h | 1 + 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/buffer_tree.c b/buffer_tree.c index 5c884709..c62cbf13 100644 --- a/buffer_tree.c +++ b/buffer_tree.c @@ -30,6 +30,8 @@ struct btr_buffer { int refcount; /* NULL means no buffer pool but a malloced buffer. */ struct btr_pool *pool; + /* Only relevant if pool is NULL. */ + bool dont_free; }; struct btr_buffer_reference { @@ -319,7 +321,7 @@ static void dealloc_buffer(struct btr_buffer *btrb) { if (btrb->pool) btr_pool_deallocate(btrb->pool, btrb->size); - else + else if (!btrb->dont_free) free(btrb->buf); } @@ -392,6 +394,34 @@ void btr_add_output(char *buf, size_t size, struct btr_node *btrn) add_btrb_to_children(btrb, btrn, 0); } +/** + * Insert a buffer into the buffer tree, non-freeing variant. + * + * \param buf See \ref btr_add_output(). + * \param size See \ref btr_add_output(). + * \param btrn See \ref btr_add_output(). + * + * This is similar to btr_add_output() but additionally sets the \p dont_free + * flag on \a buf. If the refcount for the buffer drops to zero, \a buf will + * not be deallocated if this flag is set. + * + * The \p dont_free bit also prevents the children of \a btrn from modifying + * the buffer contents inplace. Specifically, \ref btr_inplace_ok() returns + * false if there is any buffer in the input queue with the \p dont_free bit + * set. + */ +void btr_add_output_dont_free(const char *buf, size_t size, struct btr_node *btrn) +{ + struct btr_buffer *btrb; + + assert(size != 0); + if (list_empty(&btrn->children)) + return; + btrb = new_btrb((char *)buf, size); + btrb->dont_free = true; + add_btrb_to_children(btrb, btrn, 0); +} + /** * Feed data to child nodes of a buffer tree node. * @@ -544,9 +574,15 @@ bool btr_no_parent(struct btr_node *btrn) */ bool btr_inplace_ok(struct btr_node *btrn) { - if (!btrn->parent) - return true; - return list_is_singular(&btrn->parent->children); + struct btr_buffer_reference *br; + FOR_EACH_BUFFER_REF(br, btrn) { + struct btr_buffer *btrb = br->btrb; + if (btrb->refcount > 1) + return false; + if (btrb->dont_free == true) + return false; + } + return true; } static inline size_t br_available_bytes(struct btr_buffer_reference *br) diff --git a/buffer_tree.h b/buffer_tree.h index 91106a19..8e8d341d 100644 --- a/buffer_tree.h +++ b/buffer_tree.h @@ -184,6 +184,7 @@ void btr_copy(const void *src, size_t n, struct btr_pool *btrp, struct btr_node *btr_new_node(struct btr_node_description *bnd); void btr_remove_node(struct btr_node **btrnp); void btr_add_output(char *buf, size_t size, struct btr_node *btrn); +void btr_add_output_dont_free(const char *buf, size_t size, struct btr_node *btrn); size_t btr_get_input_queue_size(struct btr_node *btrn); size_t btr_get_output_queue_size(struct btr_node *btrn); bool btr_no_parent(struct btr_node *btrn); -- 2.39.5