debugger: Fix issues with restarting sessions (#33932)
Restarting sessions was broken in #33273 when we moved away from calling `kill` in the shutdown sequence. This PR re-adds that `kill` call so that old debug adapter processes will be cleaned up when sessions are restarted within Zed. This doesn't re-introduce the issue that motivated the original changes to the shutdown sequence, because we still send Disconnect/Terminate to debug adapters when quitting Zed without killing the process directly. We also now remove manually-restarted sessions eagerly from the session list. Closes #33916 Release Notes: - debugger: Fixed not being able to restart sessions for Debugpy and other adapters that communicate over TCP. - debugger: Fixed debug adapter processes not being cleaned up. --------- Co-authored-by: Remco Smits <djsmits12@gmail.com>
This commit is contained in:
parent
2a6ef006f4
commit
e0c860c42a
5 changed files with 82 additions and 62 deletions
|
@ -2,7 +2,7 @@ use crate::{
|
|||
adapters::DebugAdapterBinary,
|
||||
transport::{IoKind, LogKind, TransportDelegate},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context as _, Result};
|
||||
use dap_types::{
|
||||
messages::{Message, Response},
|
||||
requests::Request,
|
||||
|
@ -108,7 +108,11 @@ impl DebugAdapterClient {
|
|||
arguments: Some(serialized_arguments),
|
||||
};
|
||||
self.transport_delegate
|
||||
.add_pending_request(sequence_id, callback_tx);
|
||||
.pending_requests
|
||||
.lock()
|
||||
.as_mut()
|
||||
.context("client is closed")?
|
||||
.insert(sequence_id, callback_tx);
|
||||
|
||||
log::debug!(
|
||||
"Client {} send `{}` request with sequence_id: {}",
|
||||
|
|
|
@ -49,7 +49,6 @@ pub enum IoKind {
|
|||
StdErr,
|
||||
}
|
||||
|
||||
type Requests = Arc<Mutex<HashMap<u64, oneshot::Sender<Result<Response>>>>>;
|
||||
type LogHandlers = Arc<Mutex<SmallVec<[(LogKind, IoHandler); 2]>>>;
|
||||
|
||||
pub trait Transport: Send + Sync {
|
||||
|
@ -93,18 +92,14 @@ async fn start(
|
|||
|
||||
pub(crate) struct TransportDelegate {
|
||||
log_handlers: LogHandlers,
|
||||
pub(crate) pending_requests: Requests,
|
||||
// TODO this should really be some kind of associative channel
|
||||
pub(crate) pending_requests:
|
||||
Arc<Mutex<Option<HashMap<u64, oneshot::Sender<Result<Response>>>>>>,
|
||||
pub(crate) transport: Mutex<Box<dyn Transport>>,
|
||||
pub(crate) server_tx: smol::lock::Mutex<Option<Sender<Message>>>,
|
||||
tasks: Mutex<Vec<Task<()>>>,
|
||||
}
|
||||
|
||||
impl Drop for TransportDelegate {
|
||||
fn drop(&mut self) {
|
||||
self.transport.lock().kill()
|
||||
}
|
||||
}
|
||||
|
||||
impl TransportDelegate {
|
||||
pub(crate) async fn start(binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result<Self> {
|
||||
let log_handlers: LogHandlers = Default::default();
|
||||
|
@ -113,7 +108,7 @@ impl TransportDelegate {
|
|||
transport: Mutex::new(transport),
|
||||
log_handlers,
|
||||
server_tx: Default::default(),
|
||||
pending_requests: Default::default(),
|
||||
pending_requests: Arc::new(Mutex::new(Some(HashMap::default()))),
|
||||
tasks: Default::default(),
|
||||
})
|
||||
}
|
||||
|
@ -154,16 +149,26 @@ impl TransportDelegate {
|
|||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
pending_requests.lock().drain().for_each(|(_, request)| {
|
||||
request
|
||||
.send(Err(anyhow!("debugger shutdown unexpectedly")))
|
||||
.ok();
|
||||
});
|
||||
pending_requests
|
||||
.lock()
|
||||
.take()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.for_each(|(_, request)| {
|
||||
request
|
||||
.send(Err(anyhow!("debugger shutdown unexpectedly")))
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
pending_requests.lock().drain().for_each(|(_, request)| {
|
||||
request.send(Err(e.cloned())).ok();
|
||||
});
|
||||
pending_requests
|
||||
.lock()
|
||||
.take()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.for_each(|(_, request)| {
|
||||
request.send(Err(e.cloned())).ok();
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
@ -188,15 +193,6 @@ impl TransportDelegate {
|
|||
self.transport.lock().tcp_arguments()
|
||||
}
|
||||
|
||||
pub(crate) fn add_pending_request(
|
||||
&self,
|
||||
sequence_id: u64,
|
||||
request: oneshot::Sender<Result<Response>>,
|
||||
) {
|
||||
let mut pending_requests = self.pending_requests.lock();
|
||||
pending_requests.insert(sequence_id, request);
|
||||
}
|
||||
|
||||
pub(crate) async fn send_message(&self, message: Message) -> Result<()> {
|
||||
if let Some(server_tx) = self.server_tx.lock().await.as_ref() {
|
||||
server_tx.send(message).await.context("sending message")
|
||||
|
@ -290,7 +286,7 @@ impl TransportDelegate {
|
|||
async fn recv_from_server<Stdout>(
|
||||
server_stdout: Stdout,
|
||||
mut message_handler: DapMessageHandler,
|
||||
pending_requests: Requests,
|
||||
pending_requests: Arc<Mutex<Option<HashMap<u64, oneshot::Sender<Result<Response>>>>>>,
|
||||
log_handlers: Option<LogHandlers>,
|
||||
) -> Result<()>
|
||||
where
|
||||
|
@ -300,16 +296,21 @@ impl TransportDelegate {
|
|||
let mut reader = BufReader::new(server_stdout);
|
||||
|
||||
let result = loop {
|
||||
match Self::receive_server_message(&mut reader, &mut recv_buffer, log_handlers.as_ref())
|
||||
.await
|
||||
{
|
||||
let result =
|
||||
Self::receive_server_message(&mut reader, &mut recv_buffer, log_handlers.as_ref())
|
||||
.await;
|
||||
match result {
|
||||
ConnectionResult::Timeout => anyhow::bail!("Timed out when connecting to debugger"),
|
||||
ConnectionResult::ConnectionReset => {
|
||||
log::info!("Debugger closed the connection");
|
||||
return Ok(());
|
||||
break Ok(());
|
||||
}
|
||||
ConnectionResult::Result(Ok(Message::Response(res))) => {
|
||||
let tx = pending_requests.lock().remove(&res.request_seq);
|
||||
let tx = pending_requests
|
||||
.lock()
|
||||
.as_mut()
|
||||
.context("client is closed")?
|
||||
.remove(&res.request_seq);
|
||||
if let Some(tx) = tx {
|
||||
if let Err(e) = tx.send(Self::process_response(res)) {
|
||||
log::trace!("Did not send response `{:?}` for a cancelled", e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue