| 285 | } |
| 286 | |
| 287 | void PropagatorState::DeleteFrame(FrameState* frame, TaggedNodeSeq* ready) { |
| 288 | // First, propagate dead_exits (if any) to the parent frame. |
| 289 | FrameState* parent_frame = frame->parent_frame; |
| 290 | IterationState* parent_iter_state = frame->parent_iter; |
| 291 | if (parent_frame != nullptr) { |
| 292 | mutex_lock parent_frame_lock(parent_frame->mu); |
| 293 | // Propagate all the dead exits to the parent frame. |
| 294 | mutex_lock this_frame_lock(frame->mu); |
| 295 | |
| 296 | for (const NodeItem* item : frame->dead_exits) { |
| 297 | auto maybe_add_to_ready = [&](const NodeItem& dst_item, bool dst_ready, |
| 298 | bool dst_dead) { |
| 299 | if (dst_ready) { |
| 300 | // NOTE(jiankeng.pt): RunGraphOp can not be dead in any time. |
| 301 | if (dst_item.is_control_trigger || dst_item.is_run_graph_op) { |
| 302 | dst_dead = false; |
| 303 | } |
| 304 | ready->emplace_back(&dst_item, parent_frame, parent_iter_state, |
| 305 | dst_dead); |
| 306 | parent_iter_state->outstanding_ops++; |
| 307 | } |
| 308 | }; |
| 309 | |
| 310 | auto propagate_to_non_merge = [&](PendingCounts::Handle dst_pending_id) { |
| 311 | parent_iter_state->increment_dead_count(dst_pending_id); |
| 312 | return parent_iter_state->decrement_pending(dst_pending_id, 1) == 0; |
| 313 | }; |
| 314 | |
| 315 | for (const EdgeInfo& e : item->output_edges()) { |
| 316 | const NodeItem& dst_item = |
| 317 | immutable_state_.graph_view().node_ref(e.dst_id); |
| 318 | const auto dst_pending_id = immutable_state_.pending_ids()[e.dst_id]; |
| 319 | |
| 320 | bool dst_dead = true; |
| 321 | bool dst_ready; |
| 322 | // We know this is a dead input to dst. |
| 323 | if (dst_item.is_merge) { |
| 324 | parent_iter_state->increment_dead_count(dst_pending_id); |
| 325 | const int dead_cnt = parent_iter_state->dead_count(dst_pending_id); |
| 326 | dst_dead = (dead_cnt == dst_item.num_inputs); |
| 327 | dst_ready = |
| 328 | (parent_iter_state->pending(dst_pending_id) == 1) && dst_dead; |
| 329 | } else { |
| 330 | dst_ready = propagate_to_non_merge(dst_pending_id); |
| 331 | } |
| 332 | maybe_add_to_ready(dst_item, dst_ready, dst_dead); |
| 333 | } |
| 334 | |
| 335 | for (const ControlEdgeInfo& e : item->output_control_edges()) { |
| 336 | const NodeItem& dst_item = |
| 337 | immutable_state_.graph_view().node_ref(e.dst_id); |
| 338 | const auto dst_pending_id = immutable_state_.pending_ids()[e.dst_id]; |
| 339 | |
| 340 | bool dst_dead; |
| 341 | bool dst_ready; |
| 342 | // We know this is a dead input to dst. |
| 343 | if (dst_item.is_merge) { |
| 344 | parent_iter_state->decrement_pending(dst_pending_id, 2); |
nothing calls this directly
no test coverage detected