From: Andre Noll Date: Tue, 23 Aug 2011 19:04:02 +0000 (+0200) Subject: btr: Introduce btr_add_output_dont_free(). X-Git-Tag: v0.4.11~1^2~1 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=6d9c357ff64e799dfeacda6a176012de10c7f5c1;hp=4ac3134c050ba28b57e0ae9686eb1f6d83e6d586 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. --- 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);