Fix ACP connection and thread leak (#35670)
When you switched away from an ACP thread, the `AcpThreadView` entity (and thus thread, and subprocess) was leaked. This happened because we were using `cx.processor` for the `list` state callback, which uses a strong reference. This PR changes the callback so that it holds a weak reference, and adds some tests and assertions at various levels to make sure we don't reintroduce the leak in the future. Release Notes: - N/A
This commit is contained in:
parent
f27dc7dec7
commit
b7469f5bc3
8 changed files with 73 additions and 27 deletions
|
@ -169,12 +169,13 @@ impl AcpThreadView {
|
|||
|
||||
let mention_set = mention_set.clone();
|
||||
|
||||
let list_state = ListState::new(
|
||||
0,
|
||||
gpui::ListAlignment::Bottom,
|
||||
px(2048.0),
|
||||
cx.processor({
|
||||
move |this: &mut Self, index: usize, window, cx| {
|
||||
let list_state = ListState::new(0, gpui::ListAlignment::Bottom, px(2048.0), {
|
||||
let this = cx.entity().downgrade();
|
||||
move |index: usize, window, cx| {
|
||||
let Some(this) = this.upgrade() else {
|
||||
return Empty.into_any();
|
||||
};
|
||||
this.update(cx, |this, cx| {
|
||||
let Some((entry, len)) = this.thread().and_then(|thread| {
|
||||
let entries = &thread.read(cx).entries();
|
||||
Some((entries.get(index)?, entries.len()))
|
||||
|
@ -182,9 +183,9 @@ impl AcpThreadView {
|
|||
return Empty.into_any();
|
||||
};
|
||||
this.render_entry(index, len, entry, window, cx)
|
||||
}
|
||||
}),
|
||||
);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
agent: agent.clone(),
|
||||
|
@ -2719,6 +2720,16 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_drop(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let (thread_view, _cx) = setup_thread_view(StubAgentServer::default(), cx).await;
|
||||
let weak_view = thread_view.downgrade();
|
||||
drop(thread_view);
|
||||
assert!(!weak_view.is_upgradable());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_notification_for_stop_event(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
|
|
@ -970,13 +970,7 @@ impl AgentPanel {
|
|||
)
|
||||
});
|
||||
|
||||
this.set_active_view(
|
||||
ActiveView::ExternalAgentThread {
|
||||
thread_view: thread_view.clone(),
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
this.set_active_view(ActiveView::ExternalAgentThread { thread_view }, window, cx);
|
||||
})
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
|
@ -1477,6 +1471,7 @@ impl AgentPanel {
|
|||
|
||||
let current_is_special = current_is_history || current_is_config;
|
||||
let new_is_special = new_is_history || new_is_config;
|
||||
let mut old_acp_thread = None;
|
||||
|
||||
match &self.active_view {
|
||||
ActiveView::Thread { thread, .. } => {
|
||||
|
@ -1488,6 +1483,9 @@ impl AgentPanel {
|
|||
});
|
||||
}
|
||||
}
|
||||
ActiveView::ExternalAgentThread { thread_view } => {
|
||||
old_acp_thread.replace(thread_view.downgrade());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -1518,6 +1516,11 @@ impl AgentPanel {
|
|||
self.active_view = new_view;
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
old_acp_thread.map_or(true, |thread| !thread.is_upgradable()),
|
||||
"AcpThreadView leaked"
|
||||
);
|
||||
|
||||
self.acp_message_history.borrow_mut().reset_position();
|
||||
|
||||
self.focus_handle(cx).focus(window);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue