X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=buffer_tree.c;h=255dc47531e9d94ebe32046ea85a0ece5be3b888;hb=refs%2Fheads%2Fpu;hp=9b5bcda13d218b118d469587f6aec605cccec1b9;hpb=7649f22106cec2c6eb8bb10f279401e1af5451d0;p=paraslash.git diff --git a/buffer_tree.c b/buffer_tree.c index 9b5bcda1..255dc475 100644 --- a/buffer_tree.c +++ b/buffer_tree.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2009 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 2009 Andre Noll , see file COPYING. */ /** \file buffer_tree.c Buffer tree and buffer pool implementations. */ #include @@ -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,7 +562,7 @@ 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); } @@ -555,7 +579,7 @@ static bool btr_no_children(struct btr_node *btrn) * 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; } @@ -574,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) { @@ -591,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; @@ -623,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; @@ -688,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); } @@ -820,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; @@ -837,6 +863,22 @@ 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. * @@ -879,7 +921,7 @@ void btr_splice_out_node(struct btr_node **btrnp) * \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; @@ -907,7 +949,7 @@ size_t btr_get_output_queue_size(struct btr_node *btrn) * * \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; @@ -937,12 +979,12 @@ int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result) * * \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); @@ -1011,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; @@ -1071,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; @@ -1117,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); @@ -1125,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; @@ -1143,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); } @@ -1185,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. @@ -1203,27 +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; - - assert(btrn); if (type != BTR_NT_LEAF && btr_no_children(btrn)) return -E_BTR_NO_CHILD; if (type != BTR_NT_ROOT && btr_eof(btrn)) - return -E_BTR_EOF; + return -E_EOF; if (btr_get_output_queue_size(btrn) > BTRN_MAX_PENDING) return 0; if (type == BTR_NT_ROOT) return 1; - 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 (min_iqs_available(min_iqs, btrn)) + return 1; + return btr_no_parent(btrn); } /** @@ -1234,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; } @@ -1249,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; }