debugger: Fix deadlock in on_app_quit with debugger running (#29372)

This fixes a deadlock that would occur when `DapStore` had its on quit
handler called. The deadlock was caused by `DapStore` spawning on the
main thread while `App::shutdown` blocks the main thread.

We added a debug_panic in GPUI that panics if a foreground task is
spawned while the App context is shutting down. This will help tests
catch hangs in `cx.on_app_quit` calls.

Release Notes:

- N/A

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Anthony Eid
2025-04-25 14:15:10 -04:00
committed by GitHub
co-authored by Conrad Irwin
parent c3570fbcf3
commit c3177e6f5b
10 changed files with 26 additions and 162 deletions
@@ -398,14 +398,6 @@ async fn test_handle_successful_run_in_terminal_reverse_request(
assert!(running.read(cx).debug_terminal.read(cx).terminal.is_some());
})
.unwrap();
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
#[gpui::test]
@@ -478,14 +470,6 @@ async fn test_handle_start_debugging_request(
.unwrap();
assert_eq!(&fake_config, launched_with.lock().as_ref().unwrap());
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
// // covers that we always send a response back, if something when wrong,
@@ -556,14 +540,6 @@ async fn test_handle_error_run_in_terminal_reverse_request(
);
})
.unwrap();
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
#[gpui::test]
@@ -662,14 +638,6 @@ async fn test_handle_start_debugging_reverse_request(
send_response.load(std::sync::atomic::Ordering::SeqCst),
"Expected to receive response from reverse request"
);
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(child_session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
#[gpui::test]
@@ -1093,14 +1061,6 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
.update(cx, |session, cx| session.continue_thread(thread_id, cx));
});
}
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
#[gpui::test]
@@ -1256,14 +1216,6 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
called_set_breakpoints.load(std::sync::atomic::Ordering::SeqCst),
"SetBreakpoint request must be called after editor is saved"
);
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
#[gpui::test]
@@ -1383,14 +1335,6 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action(
cx.dispatch_action(crate::ClearAllBreakpoints);
cx.run_until_parked();
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)
})
});
shutdown_session.await.unwrap();
}
#[gpui::test]