@@ -73,74 +73,25 @@ auto TaskInRegistry::snapshot() -> TaskSnapshot {
73
73
74
74
namespace {
75
75
/* *
76
- Marks itself for deletion and all finishes parent nodes that do not have any
77
- other children.
76
+ Marks itself for deletion and deletes a parent reference.
78
77
79
- Loops over the hierarchy of parents of the given node. This function makes
80
- sure that these hierarchies are all marked for deletion together and can
81
- therefore be deleted in the next garbage collection run. Otherwise, a parent
82
- exists as long as its last child is not garbage collected because the child
83
- owns a shared reference to the parent, requiring as many garbage collection
84
- cycles as hierarchy levels to cleanup the given hierarchy.
85
-
86
- Some examples:
87
-
88
- If there are dependencies like (A └ B means A is parent of B)
89
- node_A
90
- └ node_B
91
- └ node (input to this function)
92
- and all of these nodes do not have any other references and are therefore
93
- finished, then this function makes sure that all of these node are marked for
94
- deletion.
95
-
96
- If we have dependencies like
97
- node_A
98
- ├ node_B
99
- └ node_C
100
- └ node (input to this function)
101
- with node_C and node beeing finished, this function will mark node_C and node
102
- for deletion but neither node_B nor node_A, independent of their state.
78
+ Deleting the parent reference makes sure that
79
+ a parent can directly be marked for deletion when all its children are
80
+ marked. Otherwise, we need to wait for the garbage collection to delete the
81
+ references, possibly requiring several garbage collection cycles to delete
82
+ all hierarchy levels.
103
83
*/
104
84
auto mark_finished_nodes_for_deletion (Node* node) {
105
- auto current_node = node;
106
- while (true ) {
107
- auto specific_node =
108
- reinterpret_cast <containers::ThreadOwnedList<TaskInRegistry>::Node*>(
109
- current_node);
110
-
111
- // make sure that we don't mark a node twice for deletion
112
- auto expected = false ;
113
- if (not specific_node->data .isDeleted .compare_exchange_strong (
114
- expected, true , std::memory_order_acq_rel)) {
115
- break ;
116
- }
117
-
118
- // do not continue if node does not have a parent
119
- auto & parent = specific_node->data .parent ;
120
- if (not std::holds_alternative<NodeReference>(parent)) {
121
- specific_node->list ->mark_for_deletion (specific_node);
122
- break ;
123
- }
124
- // do not continue if node is not the only child of parent
125
- // if child is the only reference to parent, parent is not running any more
126
- // (there is no Task that holds another shared reference) so no new children
127
- // can be added to the parent
128
- auto & parent_ref = std::get<NodeReference>(parent);
129
- if (parent_ref.use_count () != 1 ) {
130
- // if we miss decrement updates here, it does not matter:
131
- // miss 2 -> 1: parent mark for deletion is done by the other child
132
- // miss 1 -> 0: loop once more but exit early because isDeleted==true
133
- specific_node->list ->mark_for_deletion (specific_node);
134
- break ;
135
- }
85
+ auto specific_node =
86
+ reinterpret_cast <containers::ThreadOwnedList<TaskInRegistry>::Node*>(
87
+ node);
136
88
137
- // continue with parent node
138
- current_node = parent_ref. get () ;
89
+ // get rid of parent task and delete a shared reference
90
+ specific_node-> data . parent = {RootTask{}} ;
139
91
140
- // mark node for deletion needs to be last action on specific_node, because
141
- // then a garbage collection run can destroy the node at any time
142
- specific_node->list ->mark_for_deletion (specific_node);
143
- }
92
+ // mark node for deletion needs to be last action on specific_node, because
93
+ // then a garbage collection run can destroy the node at any time
94
+ specific_node->list ->mark_for_deletion (specific_node);
144
95
}
145
96
} // namespace
146
97
0 commit comments