X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_node.c;h=1ebbcf10abb8b4f4c0474cfacce4eaf3849da40b;hb=51028779e0a8772091aec5ab96bcf2519cf2f1ad;hp=7845611264ff7268b1fc553da97a7402dd9cd925;hpb=1d655de6043b607f39888c1bb88f72d071f2d49a;p=protos%2Flibecoli.git diff --git a/lib/ecoli_node.c b/lib/ecoli_node.c index 7845611..1ebbcf1 100644 --- a/lib/ecoli_node.c +++ b/lib/ecoli_node.c @@ -125,39 +125,45 @@ struct ec_node *ec_node(const char *typename, const char *id) return __ec_node(type, id); } -static void count_references(struct ec_node *node) +static void count_references(struct ec_node *node, unsigned int refs) { struct ec_node *child; size_t i, n; + int ret; if (node->free.state == EC_NODE_FREE_STATE_TRAVERSED) { - node->free.refcnt++; + node->free.refcnt += refs; return; } - node->free.refcnt = 1; + node->free.refcnt = refs; node->free.state = EC_NODE_FREE_STATE_TRAVERSED; n = ec_node_get_children_count(node); for (i = 0; i < n; i++) { - child = ec_node_get_child(node, i); - count_references(child); + ret = ec_node_get_child(node, i, &child, &refs); + assert(ret == 0); + count_references(child, refs); } } static void mark_freeable(struct ec_node *node, enum ec_node_free_state mark) { struct ec_node *child; + unsigned int refs; size_t i, n; + int ret; if (mark == node->free.state) return; - if (node->refcnt != node->free.refcnt) + if (node->refcnt > node->free.refcnt) mark = EC_NODE_FREE_STATE_NOT_FREEABLE; + assert(node->refcnt >= node->free.refcnt); node->free.state = mark; n = ec_node_get_children_count(node); for (i = 0; i < n; i++) { - child = ec_node_get_child(node, i); + ret = ec_node_get_child(node, i, &child, &refs); + assert(ret == 0); mark_freeable(child, mark); } } @@ -165,7 +171,9 @@ static void mark_freeable(struct ec_node *node, enum ec_node_free_state mark) static void reset_mark(struct ec_node *node) { struct ec_node *child; + unsigned int refs; size_t i, n; + int ret; if (node->free.state == EC_NODE_FREE_STATE_NONE) return; @@ -175,7 +183,8 @@ static void reset_mark(struct ec_node *node) n = ec_node_get_children_count(node); for (i = 0; i < n; i++) { - child = ec_node_get_child(node, i); + ret = ec_node_get_child(node, i, &child, &refs); + assert(ret == 0); reset_mark(child); } } @@ -183,8 +192,7 @@ static void reset_mark(struct ec_node *node) /* free a node, taking care of loops in the node graph */ void ec_node_free(struct ec_node *node) { - struct ec_node *child; - size_t i, n; + size_t n; if (node == NULL) return; @@ -201,7 +209,7 @@ void ec_node_free(struct ec_node *node) * node reachable from an unfreeable node is also marked as * unfreeable. */ if (node->free.state == EC_NODE_FREE_STATE_NONE) { - count_references(node); + count_references(node, 1); mark_freeable(node, EC_NODE_FREE_STATE_FREEABLE); } } @@ -215,10 +223,10 @@ void ec_node_free(struct ec_node *node) if (node->free.state != EC_NODE_FREE_STATE_FREEING) { node->free.state = EC_NODE_FREE_STATE_FREEING; n = ec_node_get_children_count(node); - for (i = 0; i < n; i++) { - child = ec_node_get_child(node, i); - ec_node_free(child); - } + /* children should be freed by free_priv() */ + assert(n == 0 || node->type->free_priv != NULL); + if (node->type->free_priv != NULL) + node->type->free_priv(node); } node->refcnt--; @@ -228,8 +236,6 @@ void ec_node_free(struct ec_node *node) node->free.state = EC_NODE_FREE_STATE_NONE; node->free.refcnt = 0; - if (node->type != NULL && node->type->free_priv != NULL) - node->type->free_priv(node); ec_free(node->id); ec_free(node->desc); ec_keyval_free(node->attrs); @@ -251,12 +257,15 @@ size_t ec_node_get_children_count(const struct ec_node *node) return node->type->get_children_count(node); } -struct ec_node * -ec_node_get_child(const struct ec_node *node, size_t i) +int +ec_node_get_child(const struct ec_node *node, size_t i, + struct ec_node **child, unsigned int *refs) { + *child = NULL; + *refs = 0; if (node->type->get_child == NULL) - return NULL; - return node->type->get_child(node, i); + return -1; + return node->type->get_child(node, i, child, refs); } int @@ -291,19 +300,22 @@ const struct ec_config *ec_node_get_config(struct ec_node *node) struct ec_node *ec_node_find(struct ec_node *node, const char *id) { - struct ec_node *child, *ret; + struct ec_node *child, *retnode; const char *node_id = ec_node_id(node); + unsigned int refs; size_t i, n; + int ret; if (id != NULL && node_id != NULL && !strcmp(node_id, id)) return node; n = ec_node_get_children_count(node); for (i = 0; i < n; i++) { - child = ec_node_get_child(node, i); - ret = ec_node_find(child, id); - if (ret != NULL) - return ret; + ret = ec_node_get_child(node, i, &child, &refs); + assert(ret == 0); + retnode = ec_node_find(child, id); + if (retnode != NULL) + return retnode; } return NULL; @@ -329,8 +341,10 @@ static void __ec_node_dump(FILE *out, { const char *id, *typename; struct ec_node *child; + unsigned int refs; char buf[32]; size_t i, n; + int ret; id = ec_node_id(node); typename = node->type->name; @@ -343,13 +357,14 @@ static void __ec_node_dump(FILE *out, } ec_keyval_set(dict, buf, NULL, NULL); - fprintf(out, "%*s" "type=%s id=%s %p refs=%u free=(%d,%d)\n", + fprintf(out, "%*s" "type=%s id=%s %p refs=%u free_state=%d free_refs=%d\n", (int)indent * 4, "", typename, id, node, node->refcnt, node->free.state, node->free.refcnt); n = ec_node_get_children_count(node); for (i = 0; i < n; i++) { - child = ec_node_get_child(node, i); + ret = ec_node_get_child(node, i, &child, &refs); + assert(ret == 0); __ec_node_dump(out, child, indent + 1, dict); } } @@ -403,8 +418,9 @@ static int ec_node_testcase(void) { struct ec_node *node = NULL, *expr = NULL; struct ec_node *expr2 = NULL, *val = NULL, *op = NULL, *seq = NULL; - const struct ec_node *child; const struct ec_node_type *type; + struct ec_node *child; + unsigned int refs; FILE *f = NULL; char *buf = NULL; size_t buflen = 0; @@ -448,17 +464,21 @@ static int ec_node_testcase(void) testres |= EC_TEST_CHECK( ec_node_get_children_count(node) == 2, "bad children count\n"); - child = ec_node_get_child(node, 0); - testres |= EC_TEST_CHECK(child != NULL && + ret = ec_node_get_child(node, 0, &child, &refs); + testres |= EC_TEST_CHECK(ret == 0 && + child != NULL && !strcmp(ec_node_type(child)->name, "str") && !strcmp(ec_node_id(child), "id_x"), "bad child 0"); - child = ec_node_get_child(node, 1); - testres |= EC_TEST_CHECK(child != NULL && + ret = ec_node_get_child(node, 1, &child, &refs); + testres |= EC_TEST_CHECK(ret == 0 && + child != NULL && !strcmp(ec_node_type(child)->name, "str") && !strcmp(ec_node_id(child), "id_y"), "bad child 1"); - child = ec_node_get_child(node, 2); + ret = ec_node_get_child(node, 2, &child, &refs); + testres |= EC_TEST_CHECK(ret != 0, + "ret should be != 0"); testres |= EC_TEST_CHECK(child == NULL, "child 2 should be NULL");