X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Fgraph%2Fgraph.c;h=808296f74f52c0828bf4c95468158d18d71506a9;hb=bd14d76835630e092320c8a04300088242dcdc99;hp=90eb92fcdd2c0f257dbdd28ab1035da0ec82dcfd;hpb=4a6b963eb0e4e9545deacfc74d81d3b9f96f060f;p=babeltrace.git diff --git a/lib/graph/graph.c b/lib/graph/graph.c index 90eb92fc..808296f7 100644 --- a/lib/graph/graph.c +++ b/lib/graph/graph.c @@ -49,12 +49,40 @@ void bt_graph_destroy(struct bt_object *obj) struct bt_graph *graph = container_of(obj, struct bt_graph, base); - if (graph->components) { - g_ptr_array_free(graph->components, TRUE); - } + /* + * The graph's reference count is 0 if we're here. Increment + * it to avoid a double-destroy (possibly infinitely recursive) + * in this situation: + * + * 1. We put and destroy a connection. + * 2. This connection's destructor finalizes its active + * notification iterators. + * 3. A notification iterator's finalization function gets a + * new reference on its component (reference count goes from + * 0 to 1). + * 4. Since this component's reference count goes to 1, it takes + * a reference on its parent (this graph). This graph's + * reference count goes from 0 to 1. + * 5. The notification iterator's finalization function puts its + * component reference (reference count goes from 1 to 0). + * 6. Since this component's reference count goes from 1 to 0, + * it puts its parent (this graph). This graph's reference + * count goes from 1 to 0. + * 7. Since this graph's reference count goes from 1 to 0, + * its destructor is called (this function). + * + * With the incrementation below, the graph's reference count at + * step 4 goes from 1 to 2, and from 2 to 1 at step 6. This + * ensures that this function is not called two times. + */ + obj->ref_count.count++; + if (graph->connections) { g_ptr_array_free(graph->connections, TRUE); } + if (graph->components) { + g_ptr_array_free(graph->components, TRUE); + } if (graph->sinks_to_consume) { g_queue_free(graph->sinks_to_consume); }