]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - buffer_tree.c
Merge topic branch t/sf_float into pu
[paraslash.git] / buffer_tree.c
index aa9f1cdb0c95b77635981cea0e6bb1588bbcdc03..255dc47531e9d94ebe32046ea85a0ece5be3b888 100644 (file)
@@ -1,8 +1,4 @@
-/*
- * Copyright (C) 2009-2013 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2009 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
 /** \file buffer_tree.c Buffer tree and buffer pool implementations. */
 #include <regex.h>
@@ -76,8 +72,8 @@ struct btr_pool *btr_pool_new(const char *name, size_t area_size)
        struct btr_pool *btrp;
 
        PARA_INFO_LOG("%s, %zu bytes\n", name, area_size);
-       btrp = para_malloc(sizeof(*btrp));
-       btrp->area_start = para_malloc(area_size);
+       btrp = alloc(sizeof(*btrp));
+       btrp->area_start = alloc(area_size);
        btrp->area_end = btrp->area_start + area_size;
        btrp->rhead = btrp->area_start;
        btrp->whead = btrp->area_start;
@@ -107,12 +103,12 @@ void btr_pool_free(struct btr_pool *btrp)
  * \return The same value which was passed during creation time to
  * btr_pool_new().
  */
-size_t btr_pool_size(struct btr_pool *btrp)
+size_t btr_pool_size(const struct btr_pool *btrp)
 {
        return btrp->area_end - btrp->area_start;
 }
 
-static size_t btr_pool_filled(struct btr_pool *btrp)
+static size_t btr_pool_filled(const struct btr_pool *btrp)
 {
        if (!btrp->whead)
                return btr_pool_size(btrp);
@@ -133,7 +129,7 @@ static size_t btr_pool_filled(struct btr_pool *btrp)
  * the largest contiguous buffer that can currently be allocated from the
  * buffer pool.
  */
-size_t btr_pool_unused(struct btr_pool *btrp)
+size_t btr_pool_unused(const struct btr_pool *btrp)
 {
        return btr_pool_size(btrp) - btr_pool_filled(btrp);
 }
@@ -142,7 +138,7 @@ size_t btr_pool_unused(struct btr_pool *btrp)
  * Return maximal size available for one read. This is
  * smaller than the value returned by btr_pool_unused().
  */
-static size_t btr_pool_available(struct btr_pool *btrp)
+static size_t btr_pool_available(const struct btr_pool *btrp)
 {
        if (!btrp->whead)
                return 0;
@@ -160,7 +156,7 @@ static size_t btr_pool_available(struct btr_pool *btrp)
  * \return The maximal amount of bytes that may be written to the returned
  * buffer.
  */
-size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result)
+size_t btr_pool_get_buffer(const struct btr_pool *btrp, char **result)
 {
        if (result)
                *result = btrp->whead;
@@ -178,7 +174,7 @@ size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result)
  * consists of two buffers. If this function returns the value n, then n
  * elements of \a iov are initialized.
  */
-int btr_pool_get_buffers(struct btr_pool *btrp, struct iovec iov[2])
+int btr_pool_get_buffers(const struct btr_pool *btrp, struct iovec iov[2])
 {
        size_t sz, unused;
        char *buf;
@@ -266,7 +262,7 @@ static void btr_pool_deallocate(struct btr_pool *btrp, size_t size)
  */
 struct btr_node *btr_new_node(struct btr_node_description *bnd)
 {
-       struct btr_node *btrn = para_malloc(sizeof(*btrn));
+       struct btr_node *btrn = alloc(sizeof(*btrn));
 
        btrn->name = para_strdup(bnd->name);
        btrn->parent = bnd->parent;
@@ -274,8 +270,8 @@ struct btr_node *btr_new_node(struct btr_node_description *bnd)
        btrn->context = bnd->context;
        btrn->start.tv_sec = 0;
        btrn->start.tv_usec = 0;
-       INIT_LIST_HEAD(&btrn->children);
-       INIT_LIST_HEAD(&btrn->input_queue);
+       init_list_head(&btrn->children);
+       init_list_head(&btrn->input_queue);
        if (!bnd->child) {
                if (bnd->parent) {
                        list_add_tail(&btrn->node, &bnd->parent->children);
@@ -311,7 +307,7 @@ out:
  */
 static struct btr_buffer *new_btrb(char *buf, size_t size)
 {
-       struct btr_buffer *btrb = para_calloc(sizeof(*btrb));
+       struct btr_buffer *btrb = zalloc(sizeof(*btrb));
 
        btrb->buf = buf;
        btrb->size = size;
@@ -326,7 +322,7 @@ static void dealloc_buffer(struct btr_buffer *btrb)
                free(btrb->buf);
 }
 
-static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn)
+static struct btr_buffer_reference *get_first_input_br(const struct btr_node *btrn)
 {
        if (list_empty(&btrn->input_queue))
                return NULL;
@@ -334,6 +330,14 @@ static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn)
                struct btr_buffer_reference, node);
 }
 
+static struct btr_buffer_reference *get_last_input_br(const struct btr_node *btrn)
+{
+       if (list_empty(&btrn->input_queue))
+               return NULL;
+       return list_last_entry(&btrn->input_queue,
+               struct btr_buffer_reference, node);
+}
+
 /*
  * Deallocate the reference, release the resources if refcount drops to zero.
  */
@@ -350,6 +354,20 @@ static void btr_drop_buffer_reference(struct btr_buffer_reference *br)
        }
 }
 
+static bool may_merge_btrb(const struct btr_buffer *btrb,
+               const struct btr_buffer_reference *br)
+{
+       if (!br)
+               return false;
+       if (br->consumed > 0)
+               return false;
+       if (br->btrb->buf + br->btrb->size != btrb->buf)
+               return false;
+       if (!br->btrb->pool)
+               return true;
+       return br->btrb->size + btrb->size < btr_pool_size(br->btrb->pool) / 3;
+}
+
 static void add_btrb_to_children(struct btr_buffer *btrb,
                struct btr_node *btrn, size_t consumed)
 {
@@ -358,11 +376,17 @@ static void add_btrb_to_children(struct btr_buffer *btrb,
        if (btrn->start.tv_sec == 0)
                btrn->start = *now;
        FOR_EACH_CHILD(ch, btrn) {
-               struct btr_buffer_reference *br = para_calloc(sizeof(*br));
-               br->btrb = btrb;
-               br->consumed = consumed;
-               list_add_tail(&br->node, &ch->input_queue);
-               btrb->refcount++;
+               struct btr_buffer_reference *br = get_last_input_br(ch);
+               if (may_merge_btrb(btrb, br)) {
+                       br->btrb->size += btrb->size;
+                       free(btrb);
+               } else {
+                       br = zalloc(sizeof(*br));
+                       br->btrb = btrb;
+                       br->consumed = consumed;
+                       list_add_tail(&br->node, &ch->input_queue);
+                       btrb->refcount++;
+               }
                if (ch->start.tv_sec == 0)
                        ch->start = *now;
        }
@@ -538,22 +562,24 @@ void btr_pushdown_one(struct btr_node *btrn)
  *
  * \return True if this node has no children. False otherwise.
  */
-static bool btr_no_children(struct btr_node *btrn)
+static bool btr_no_children(const struct btr_node *btrn)
 {
        return list_empty(&btrn->children);
 }
 
 /**
- * Find out whether a node is an orphan node.
+ * Find out whether a node is an orphan.
  *
  * \param btrn The buffer tree node.
  *
  * \return True if \a btrn has no parent.
  *
- * This function will always return true for the root node.  However in case
- * nodes have been removed from the tree, other nodes may become orphans too.
+ * This function returns true for the root node and false for any other node.
+ *
+ * After a (non-leaf) node was removed removed from the tree, the function
+ * returns true for all child nodes.
  */
-bool btr_no_parent(struct btr_node *btrn)
+bool btr_no_parent(const struct btr_node *btrn)
 {
        return !btrn->parent;
 }
@@ -572,11 +598,11 @@ bool btr_no_parent(struct btr_node *btrn)
  * buffer.
  *
  * Since the buffer tree may change at any time, this function should be called
- * during each post_select call.
+ * during each post_monitor call.
  *
  * \return True if \a btrn has no siblings.
  */
-bool btr_inplace_ok(struct btr_node *btrn)
+bool btr_inplace_ok(const struct btr_node *btrn)
 {
        struct btr_buffer_reference *br;
        FOR_EACH_BUFFER_REF(br, btrn) {
@@ -589,12 +615,13 @@ bool btr_inplace_ok(struct btr_node *btrn)
        return true;
 }
 
-static inline size_t br_available_bytes(struct btr_buffer_reference *br)
+static inline size_t br_available_bytes(const struct btr_buffer_reference *br)
 {
        return br->btrb->size - br->consumed;
 }
 
-static size_t btr_get_buffer_by_reference(struct btr_buffer_reference *br, char **buf)
+static size_t btr_get_buffer_by_reference(const struct btr_buffer_reference *br,
+               char **buf)
 {
        if (buf)
                *buf = br->btrb->buf + br->consumed;
@@ -621,7 +648,8 @@ static size_t btr_get_buffer_by_reference(struct btr_buffer_reference *br, char
  * to by \a btrn, the function returns zero and the value of \a bufp is
  * undefined.
  */
-size_t btr_next_buffer_omit(struct btr_node *btrn, size_t omit, char **bufp)
+size_t btr_next_buffer_omit(const struct btr_node *btrn, size_t omit,
+               char **bufp)
 {
        struct btr_buffer_reference *br;
        size_t wrap_count, sz, rv = 0;
@@ -686,7 +714,7 @@ out:
  * The call of this function is is equivalent to calling \ref
  * btr_next_buffer_omit() with an \a omit value of zero.
  */
-size_t btr_next_buffer(struct btr_node *btrn, char **bufp)
+size_t btr_next_buffer(const struct btr_node *btrn, char **bufp)
 {
        return btr_next_buffer_omit(btrn, 0, bufp);
 }
@@ -769,6 +797,12 @@ void btr_drain(struct btr_node *btrn)
                btr_drop_buffer_reference(br);
 }
 
+static void btr_free_node(struct btr_node *btrn)
+{
+       free(btrn->name);
+       free(btrn);
+}
+
 /**
  * Remove a node from a buffer tree.
  *
@@ -796,8 +830,7 @@ void btr_remove_node(struct btr_node **btrnp)
        btr_drain(btrn);
        if (btrn->parent)
                list_del(&btrn->node);
-       free(btrn->name);
-       free(btrn);
+       btr_free_node(btrn);
 out:
        *btrnp = NULL;
 }
@@ -813,7 +846,7 @@ out:
  * This simply iterates over all buffer references in the input queue and
  * returns the sum of the sizes of all references.
  */
-size_t btr_get_input_queue_size(struct btr_node *btrn)
+size_t btr_get_input_queue_size(const struct btr_node *btrn)
 {
        struct btr_buffer_reference *br;
        size_t size = 0, wrap_consumed = 0;
@@ -830,10 +863,26 @@ size_t btr_get_input_queue_size(struct btr_node *btrn)
        return size;
 }
 
+static bool min_iqs_available(size_t min_iqs, const struct btr_node *btrn)
+{
+       struct btr_buffer_reference *br;
+       size_t have = 0, wrap_consumed = 0;
+
+       FOR_EACH_BUFFER_REF(br, btrn) {
+               if (br->wrap_count != 0) {
+                       wrap_consumed = br->consumed;
+                       continue;
+               }
+               have += br_available_bytes(br);
+               if (have > wrap_consumed + min_iqs)
+                       return true;
+       }
+       return false;
+}
 /**
  * Remove a node from the buffer tree, reconnecting parent and children.
  *
- * \param btrn The node to splice out.
+ * \param btrnp The node to splice out.
  *
  * This function is used by buffer tree nodes that do not exist during the
  * whole lifetime of the buffer tree. Unlike btr_remove_node(), calling
@@ -841,9 +890,9 @@ size_t btr_get_input_queue_size(struct btr_node *btrn)
  * but reconnects the buffer tree by making all child nodes of \a btrn children
  * of the parent of \a btrn.
  */
-void btr_splice_out_node(struct btr_node *btrn)
+void btr_splice_out_node(struct btr_node **btrnp)
 {
-       struct btr_node *ch, *tmp;
+       struct btr_node *btrn = *btrnp, *ch, *tmp;
 
        assert(btrn);
        PARA_NOTICE_LOG("splicing out %s\n", btrn->name);
@@ -860,7 +909,8 @@ void btr_splice_out_node(struct btr_node *btrn)
                        list_del(&ch->node);
        }
        assert(list_empty(&btrn->children));
-       btrn->parent = NULL;
+       btr_free_node(btrn);
+       *btrnp = NULL;
 }
 
 /**
@@ -871,7 +921,7 @@ void btr_splice_out_node(struct btr_node *btrn)
  * \return This function iterates over all children of the given node and
  * returns the size of the largest input queue.
  */
-size_t btr_get_output_queue_size(struct btr_node *btrn)
+size_t btr_get_output_queue_size(const struct btr_node *btrn)
 {
        size_t max_size = 0;
        struct btr_node *ch;
@@ -897,9 +947,9 @@ size_t btr_get_output_queue_size(struct btr_node *btrn)
  * \return \p -ENOTSUP if no parent node of \a btrn understands \a command.
  * Otherwise the return value of the command handler is returned.
  *
- * \sa \ref receiver::execute, filter::execute, writer::execute.
+ * \sa \ref receiver::execute, \ref filter::execute, \ref writer::execute.
  */
-int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result)
+int btr_exec_up(const struct btr_node *btrn, const char *command, char **value_result)
 {
        int ret;
 
@@ -927,14 +977,14 @@ int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result)
  *
  * \return A pointer to the \a context address specified at node creation time.
  *
- * \sa btr_new_node(), struct \ref btr_node_description.
+ * \sa \ref btr_new_node(), struct \ref btr_node_description.
  */
-void *btr_context(struct btr_node *btrn)
+void *btr_context(const struct btr_node *btrn)
 {
        return btrn->context;
 }
 
-static bool need_buffer_pool_merge(struct btr_node *btrn)
+static bool need_buffer_pool_merge(const struct btr_node *btrn)
 {
        struct btr_buffer_reference *br = get_first_input_br(btrn);
 
@@ -1003,12 +1053,12 @@ next:
        if (!wbr) {
                /* Make a new wrap buffer combining buf1 and buf2. */
                sz = sz1 + sz2;
-               buf = para_malloc(sz);
+               buf = alloc(sz);
                PARA_DEBUG_LOG("merging input buffers: (%p:%zu, %p:%zu) -> %p:%zu\n",
                        buf1, sz1, buf2, sz2, buf, sz);
                memcpy(buf, buf1, sz1);
                memcpy(buf + sz1, buf2, sz2);
-               br = para_calloc(sizeof(*br));
+               br = zalloc(sizeof(*br));
                br->btrb = new_btrb(buf, sz);
                br->btrb->refcount = 1;
                br->consumed = 0;
@@ -1063,13 +1113,13 @@ static int merge_input(struct btr_node *btrn)
        assert(i == 2);
        /* make a new btrb that combines the two buffers and a br to it. */
        sz = szs[0] + szs[1];
-       buf = para_malloc(sz);
+       buf = alloc(sz);
        PARA_DEBUG_LOG("%s: memory merging input buffers: (%zu, %zu) -> %zu\n",
                btrn->name, szs[0], szs[1], sz);
        memcpy(buf, bufs[0], szs[0]);
        memcpy(buf + szs[0], bufs[1], szs[1]);
 
-       br = para_calloc(sizeof(*br));
+       br = zalloc(sizeof(*br));
        br->btrb = new_btrb(buf, sz);
        br->btrb->refcount = 1;
 
@@ -1109,7 +1159,7 @@ void btr_merge(struct btr_node *btrn, size_t dest_size)
        }
 }
 
-static bool btr_eof(struct btr_node *btrn)
+static bool btr_eof(const struct btr_node *btrn)
 {
        char *buf;
        size_t len = btr_next_buffer(btrn, &buf);
@@ -1117,7 +1167,7 @@ static bool btr_eof(struct btr_node *btrn)
        return (len == 0 && btr_no_parent(btrn));
 }
 
-static void log_tree_recursively(struct btr_node *btrn, int loglevel, int depth)
+static void log_tree_recursively(const struct btr_node *btrn, int loglevel, int depth)
 {
        struct btr_node *ch;
        const char spaces[] = "                 ", *space = spaces + 16 - depth;
@@ -1135,7 +1185,7 @@ static void log_tree_recursively(struct btr_node *btrn, int loglevel, int depth)
  * \param btrn Start logging at this node.
  * \param loglevel Set severity with which the tree should be logged.
  */
-void btr_log_tree(struct btr_node *btrn, int loglevel)
+void btr_log_tree(const struct btr_node *btrn, int loglevel)
 {
        return log_tree_recursively(btrn, loglevel, 0);
 }
@@ -1177,7 +1227,7 @@ struct btr_node *btr_search_node(const char *name, struct btr_node *root)
  * \param type The supposed type of \a btrn.
  *
  * Most users of the buffer tree subsystem call this function from both
- * their pre_select and the post_select methods.
+ * their ->pre_monitor() and ->post_monitor() methods.
  *
  * \return Negative if an error condition was detected, zero if there
  * is nothing to do and positive otherwise.
@@ -1195,28 +1245,21 @@ struct btr_node *btr_search_node(const char *name, struct btr_node *root)
  * btrn, the function also returns zero in order to bound the memory usage of
  * the buffer tree.
  */
-int btr_node_status(struct btr_node *btrn, size_t min_iqs,
+int btr_node_status(const struct btr_node *btrn, size_t min_iqs,
        enum btr_node_type type)
 {
-       size_t iqs;
+       if (type != BTR_NT_LEAF && btr_no_children(btrn))
+               return -E_BTR_NO_CHILD;
+       if (type != BTR_NT_ROOT && btr_eof(btrn))
+               return -E_EOF;
 
-       assert(btrn);
-       if (type != BTR_NT_LEAF) {
-               if (btr_no_children(btrn))
-                       return -E_BTR_NO_CHILD;
-               if (btr_get_output_queue_size(btrn) > BTRN_MAX_PENDING)
-                       return 0;
-       }
-       if (type != BTR_NT_ROOT) {
-               if (btr_eof(btrn))
-                       return -E_BTR_EOF;
-               iqs = btr_get_input_queue_size(btrn);
-               if (iqs == 0) /* we have a parent, because not eof */
-                       return 0;
-               if (iqs < min_iqs && !btr_no_parent(btrn))
-                       return 0;
-       }
-       return 1;
+       if (btr_get_output_queue_size(btrn) > BTRN_MAX_PENDING)
+               return 0;
+       if (type == BTR_NT_ROOT)
+               return 1;
+       if (min_iqs_available(min_iqs, btrn))
+               return 1;
+       return btr_no_parent(btrn);
 }
 
 /**
@@ -1227,7 +1270,7 @@ int btr_node_status(struct btr_node *btrn, size_t min_iqs,
  *
  * Mainly useful for the time display of para_audiod.
  */
-void btr_get_node_start(struct btr_node *btrn, struct timeval *tv)
+void btr_get_node_start(const struct btr_node *btrn, struct timeval *tv)
 {
        *tv = btrn->start;
 }
@@ -1242,7 +1285,7 @@ void btr_get_node_start(struct btr_node *btrn, struct timeval *tv)
  * \return The parent of \a btrn, or \p NULL if \a btrn is the
  * root node of the buffer tree.
  */
-struct btr_node *btr_parent(struct btr_node *btrn)
+struct btr_node *btr_parent(const struct btr_node *btrn)
 {
        return btrn->parent;
 }