From 9c43320aa9207f35e969335f814e64cbee772c50 Mon Sep 17 00:00:00 2001 From: Yikai Zhao Date: Tue, 2 Jan 2024 23:37:47 +0800 Subject: [PATCH] correctly exit when child exit --- Cargo.toml | 2 +- src/app.rs | 62 +++++++++++++++++++++++------------------------ src/lib.rs | 2 +- src/main.rs | 3 ++- tests/app_test.rs | 35 ++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 tests/app_test.rs diff --git a/Cargo.toml b/Cargo.toml index 34634dd..e90d34f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ serde_json = "1.0" anyhow = "1.0" lazy_static = "1.4" smallvec = "1.11" -tempfile = "3.9" env_logger = "0.10" log = "0.4.20" @@ -21,3 +20,4 @@ crate-type = ["cdylib"] [dev-dependencies] emacs = "0.18" +tempfile = "3.9" diff --git a/src/app.rs b/src/app.rs index 954769d..937f02d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -86,9 +86,9 @@ fn process_server_reader(reader: impl std::io::Read, pub fn run_app_forever(client_reader: impl std::io::Read + Send + 'static, client_writer: impl std::io::Write + Send + 'static, - mut server_cmd: std::process::Command) -> Result<()> { + mut server_cmd: std::process::Command) -> Result { info!("Running server {:?}", server_cmd); - let proc = server_cmd + let mut proc = server_cmd .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::inherit()) @@ -98,37 +98,35 @@ pub fn run_app_forever(client_reader: impl std::io::Read + Send + 'static, let c2s_channel_counter = Arc::new(AtomicI32::new(0)); let (s2c_channel_pub, s2c_channel_sub) = mpsc::channel::(); - let threads = vec![ - { - let c2s_channel_counter = c2s_channel_counter.clone(); - std::thread::spawn(move || { - info!("Started client->server write thread"); - process_channel_to_writer(c2s_channel_sub, Some(c2s_channel_counter), proc.stdin.unwrap()).unwrap(); - info!("Finished client->server write thread"); - }) - }, + { + let c2s_channel_counter = c2s_channel_counter.clone(); + let proc_stdin = proc.stdin.take().unwrap(); std::thread::spawn(move || { - info!("Started server->client write thread"); - process_channel_to_writer(s2c_channel_sub, None, client_writer).unwrap(); - info!("Finished server->client write thread"); - }), - { - let s2c_channel_pub = s2c_channel_pub.clone(); - std::thread::spawn(move || { - info!("Started server->client read thread"); - process_server_reader(proc.stdout.unwrap(), s2c_channel_pub).unwrap(); - info!("Finished server->client read thread"); - }) - }, + info!("Started client->server write thread"); + process_channel_to_writer(c2s_channel_sub, Some(c2s_channel_counter), proc_stdin).unwrap(); + info!("Finished client->server write thread"); + }); + } + std::thread::spawn(move || { + info!("Started server->client write thread"); + process_channel_to_writer(s2c_channel_sub, None, client_writer).unwrap(); + info!("Finished server->client write thread"); + }); + { + let s2c_channel_pub = s2c_channel_pub.clone(); + let proc_stdout = proc.stdout.take().unwrap(); std::thread::spawn(move || { - info!("Started client->server read thread"); - process_client_reader( - client_reader, c2s_channel_pub, c2s_channel_counter, s2c_channel_pub).unwrap(); - info!("Finished client->server read thread"); - }), - ]; - - threads.into_iter().for_each(|x| x.join().unwrap()); + info!("Started server->client read thread"); + process_server_reader(proc_stdout, s2c_channel_pub).unwrap(); + info!("Finished server->client read thread"); + }); + } + std::thread::spawn(move || { + info!("Started client->server read thread"); + process_client_reader( + client_reader, c2s_channel_pub, c2s_channel_counter, s2c_channel_pub).unwrap(); + info!("Finished client->server read thread"); + }); - Ok(()) + Ok(proc.wait()?) } diff --git a/src/lib.rs b/src/lib.rs index 17a1c92..af4f2ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ pub mod bytecode; -mod rpcio; +pub mod rpcio; mod lsp_message; pub mod app; diff --git a/src/main.rs b/src/main.rs index 22965a6..146d000 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,5 +24,6 @@ fn main() -> Result<()> { let mut cmd = std::process::Command::new(&args[1]); cmd.args(&args[2..]); - app::run_app_forever(std::io::stdin(), std::io::stdout(), cmd) + let exit_status = app::run_app_forever(std::io::stdin(), std::io::stdout(), cmd)?; + std::process::exit(exit_status.code().unwrap_or(1)) } diff --git a/tests/app_test.rs b/tests/app_test.rs new file mode 100644 index 0000000..61d9a38 --- /dev/null +++ b/tests/app_test.rs @@ -0,0 +1,35 @@ +use anyhow::Result; +use tempfile; +use env_logger; + +use emacs_lsp_booster::{app, rpcio}; + +#[test] +fn test_app_with_echo_server() -> Result<()> { + env_logger::init(); + + let (input_pair_in, input_pair_out) = std::os::unix::net::UnixStream::pair()?; + let tmpdir = tempfile::tempdir()?; + let output_file = std::fs::File::create(tmpdir.path().join("output.txt"))?; + + std::thread::spawn(move || { + let mut input_bufwriter = std::io::BufWriter::new(input_pair_in); + for _ in 0..10 { + rpcio::rpc_write(&mut input_bufwriter, "{}").unwrap(); + } + loop { + std::thread::park(); + } + }); + + let mut cmd = std::process::Command::new("timeout"); + cmd.args(&["1", "cat"]); + + let exit_status = app::run_app_forever(input_pair_out, output_file, cmd)?; + assert!(!exit_status.success()); // timeout kill + + let output = std::fs::read_to_string(tmpdir.path().join("output.txt"))?; + assert_eq!(output.chars().filter(|x| *x == '#').count(), 10); + + Ok(()) +}