diff --git a/src/runtime2/component/component.rs b/src/runtime2/component/component.rs index e350d706a207397f98e63d266c188ed64efcefec..2a49e852f3e325391f077e5ea1978c0524b1fd9c 100644 --- a/src/runtime2/component/component.rs +++ b/src/runtime2/component/component.rs @@ -216,6 +216,62 @@ pub(crate) fn default_handle_control_message( } } +/// Handles a component initiating the exiting procedure, and closing all of its +/// ports. Should only be called once per component (which is ensured by +/// checking and modifying the mode in the execution state). +pub(crate) fn default_handle_start_exit( + exec_state: &mut CompExecState, control: &mut ControlLayer, + sched_ctx: &SchedulerCtx, comp_ctx: &mut CompCtx +) -> CompScheduling { + debug_assert_eq!(exec_state.mode, CompMode::StartExit); + sched_ctx.log("Component starting exit"); + exec_state.mode = CompMode::BusyExit; + + // Iterating by index to work around borrowing rules + for port_index in 0..comp_ctx.num_ports() { + let port = comp_ctx.get_port_by_index_mut(port_index); + if port.state == PortState::Closed { + // Already closed, or in the process of being closed + continue; + } + + // Mark as closed + let port_id = port.self_id; + port.state = PortState::Closed; + + // Notify peer of closing + let port_handle = comp_ctx.get_port_handle(port_id); + let (peer, message) = control.initiate_port_closing(port_handle, comp_ctx); + let peer_info = comp_ctx.get_peer(peer); + peer_info.handle.send_message(sched_ctx, Message::Control(message), true); + } + + return CompScheduling::Immediate; // to check if we can shut down immediately +} + +/// Handles a component waiting until all peers are notified that it is quitting +/// (i.e. after calling `default_handle_start_exit`). +pub(crate) fn default_handle_busy_exit( + exec_state: &mut CompExecState, control: &ControlLayer, + sched_ctx: &SchedulerCtx +) -> CompScheduling { + debug_assert_eq!(exec_state.mode, CompMode::BusyExit); + if control.has_acks_remaining() { + sched_ctx.log("Component busy exiting, still has `Ack`s remaining"); + return CompScheduling::Sleep; + } else { + sched_ctx.log("Component busy exiting, now shutting down"); + exec_state.mode = CompMode::Exit; + return CompScheduling::Exit; + } +} + +#[inline] +pub(crate) fn default_handle_exit(_exec_state: &CompExecState) -> CompScheduling { + debug_assert_eq!(exec_state.mode, CompMode::Exit); + return CompScheduling::Exit; +} + // ----------------------------------------------------------------------------- // Internal messaging/state utilities // -----------------------------------------------------------------------------