Skip to content

Commit 091dbfe

Browse files
Merge #9535
9535: internal: remove proc macro management thread r=jonas-schievink a=jonas-schievink Communication with the proc macro server process has always happened one request at a time, so the additional thread isn't really needed (it just forwarded each request, and sent back the response). This removes some indirection that was a bit hard to understand (a channel was allocated and sent over another channel to return the response). Hope I'm not missing anything here Co-authored-by: Jonas Schievink <[email protected]>
2 parents fe00358 + 29db33c commit 091dbfe

File tree

3 files changed

+55
-80
lines changed

3 files changed

+55
-80
lines changed

crates/proc_macro_api/src/lib.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ use std::{
1515
ffi::OsStr,
1616
io,
1717
path::{Path, PathBuf},
18-
sync::Arc,
18+
sync::{Arc, Mutex},
1919
};
2020

2121
use tt::{SmolStr, Subtree};
2222

23-
use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
23+
use crate::process::ProcMacroProcessSrv;
2424

2525
pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
2626
pub use version::{read_dylib_info, RustCInfo};
2727

2828
#[derive(Debug, Clone)]
2929
struct ProcMacroProcessExpander {
30-
process: Arc<ProcMacroProcessSrv>,
30+
process: Arc<Mutex<ProcMacroProcessSrv>>,
3131
dylib_path: PathBuf,
3232
name: SmolStr,
3333
}
@@ -56,24 +56,34 @@ impl base_db::ProcMacroExpander for ProcMacroProcessExpander {
5656
env: env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
5757
};
5858

59-
let result: ExpansionResult = self.process.send_task(msg::Request::ExpansionMacro(task))?;
59+
let result: ExpansionResult = self
60+
.process
61+
.lock()
62+
.unwrap_or_else(|e| e.into_inner())
63+
.send_task(msg::Request::ExpansionMacro(task))?;
6064
Ok(result.expansion)
6165
}
6266
}
6367

6468
#[derive(Debug)]
6569
pub struct ProcMacroClient {
66-
process: Arc<ProcMacroProcessSrv>,
67-
thread: ProcMacroProcessThread,
70+
/// Currently, the proc macro process expands all procedural macros sequentially.
71+
///
72+
/// That means that concurrent salsa requests may block each other when expanding proc macros,
73+
/// which is unfortunate, but simple and good enough for the time being.
74+
///
75+
/// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here.
76+
process: Arc<Mutex<ProcMacroProcessSrv>>,
6877
}
6978

7079
impl ProcMacroClient {
80+
/// Spawns an external process as the proc macro server and returns a client connected to it.
7181
pub fn extern_process(
7282
process_path: PathBuf,
7383
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
7484
) -> io::Result<ProcMacroClient> {
75-
let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
76-
Ok(ProcMacroClient { process: Arc::new(process), thread })
85+
let process = ProcMacroProcessSrv::run(process_path, args)?;
86+
Ok(ProcMacroClient { process: Arc::new(Mutex::new(process)) })
7787
}
7888

7989
pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> {
@@ -93,7 +103,12 @@ impl ProcMacroClient {
93103
}
94104
}
95105

96-
let macros = match self.process.find_proc_macros(dylib_path) {
106+
let macros = match self
107+
.process
108+
.lock()
109+
.unwrap_or_else(|e| e.into_inner())
110+
.find_proc_macros(dylib_path)
111+
{
97112
Err(err) => {
98113
eprintln!("Failed to find proc macros. Error: {:#?}", err);
99114
return vec![];

crates/proc_macro_api/src/process.rs

Lines changed: 30 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,38 @@ use std::{
55
ffi::{OsStr, OsString},
66
io::{self, BufRead, BufReader, Write},
77
path::{Path, PathBuf},
8-
process::{Child, Command, Stdio},
9-
sync::{Arc, Weak},
8+
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
109
};
1110

12-
use crossbeam_channel::{bounded, Receiver, Sender};
1311
use stdx::JodChild;
1412

1513
use crate::{
1614
msg::{ErrorCode, Message, Request, Response, ResponseError},
1715
rpc::{ListMacrosResult, ListMacrosTask, ProcMacroKind},
1816
};
1917

20-
#[derive(Debug, Default)]
21-
pub(crate) struct ProcMacroProcessSrv {
22-
inner: Weak<Sender<Task>>,
23-
}
24-
2518
#[derive(Debug)]
26-
pub(crate) struct ProcMacroProcessThread {
27-
// XXX: drop order is significant
28-
sender: Arc<Sender<Task>>,
29-
handle: jod_thread::JoinHandle<()>,
19+
pub(crate) struct ProcMacroProcessSrv {
20+
process: Process,
21+
stdin: ChildStdin,
22+
stdout: BufReader<ChildStdout>,
3023
}
3124

3225
impl ProcMacroProcessSrv {
3326
pub(crate) fn run(
3427
process_path: PathBuf,
3528
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
36-
) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
37-
let process = Process::run(process_path, args)?;
38-
39-
let (task_tx, task_rx) = bounded(0);
40-
let handle = jod_thread::Builder::new()
41-
.name("ProcMacroClient".to_owned())
42-
.spawn(move || {
43-
client_loop(task_rx, process);
44-
})
45-
.expect("failed to spawn thread");
46-
47-
let task_tx = Arc::new(task_tx);
48-
let srv = ProcMacroProcessSrv { inner: Arc::downgrade(&task_tx) };
49-
let thread = ProcMacroProcessThread { handle, sender: task_tx };
50-
51-
Ok((thread, srv))
29+
) -> io::Result<ProcMacroProcessSrv> {
30+
let mut process = Process::run(process_path, args)?;
31+
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
32+
33+
let srv = ProcMacroProcessSrv { process, stdin, stdout };
34+
35+
Ok(srv)
5236
}
5337

5438
pub(crate) fn find_proc_macros(
55-
&self,
39+
&mut self,
5640
dylib_path: &Path,
5741
) -> Result<Vec<(String, ProcMacroKind)>, tt::ExpansionError> {
5842
let task = ListMacrosTask { lib: dylib_path.to_path_buf() };
@@ -61,64 +45,39 @@ impl ProcMacroProcessSrv {
6145
Ok(result.macros)
6246
}
6347

64-
pub(crate) fn send_task<R>(&self, req: Request) -> Result<R, tt::ExpansionError>
48+
pub(crate) fn send_task<R>(&mut self, req: Request) -> Result<R, tt::ExpansionError>
6549
where
6650
R: TryFrom<Response, Error = &'static str>,
6751
{
68-
let (result_tx, result_rx) = bounded(0);
69-
let sender = match self.inner.upgrade() {
70-
None => return Err(tt::ExpansionError::Unknown("proc macro process is closed".into())),
71-
Some(it) => it,
72-
};
73-
sender
74-
.send(Task { req, result_tx })
75-
.map_err(|_| tt::ExpansionError::Unknown("proc macro server crashed".into()))?;
76-
77-
let res = result_rx
78-
.recv()
79-
.map_err(|_| tt::ExpansionError::Unknown("proc macro server crashed".into()))?;
80-
81-
match res {
82-
Some(Response::Error(err)) => Err(tt::ExpansionError::ExpansionError(err.message)),
83-
Some(res) => Ok(res.try_into().map_err(|err| {
84-
tt::ExpansionError::Unknown(format!("Fail to get response, reason : {:#?} ", err))
85-
})?),
86-
None => Err(tt::ExpansionError::Unknown("Empty result".into())),
87-
}
88-
}
89-
}
90-
91-
fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
92-
let (mut stdin, mut stdout) = process.stdio().expect("couldn't access child stdio");
93-
94-
let mut buf = String::new();
95-
96-
for Task { req, result_tx } in task_rx {
97-
match send_request(&mut stdin, &mut stdout, req, &mut buf) {
98-
Ok(res) => result_tx.send(res).unwrap(),
52+
let mut buf = String::new();
53+
let res = match send_request(&mut self.stdin, &mut self.stdout, req, &mut buf) {
54+
Ok(res) => res,
9955
Err(err) => {
56+
let result = self.process.child.try_wait();
10057
log::error!(
10158
"proc macro server crashed, server process state: {:?}, server request error: {:?}",
102-
process.child.try_wait(),
59+
result,
10360
err
10461
);
10562
let res = Response::Error(ResponseError {
10663
code: ErrorCode::ServerErrorEnd,
10764
message: "proc macro server crashed".into(),
10865
});
109-
result_tx.send(res.into()).unwrap();
110-
// Exit the thread.
111-
break;
66+
Some(res)
11267
}
68+
};
69+
70+
match res {
71+
Some(Response::Error(err)) => Err(tt::ExpansionError::ExpansionError(err.message)),
72+
Some(res) => Ok(res.try_into().map_err(|err| {
73+
tt::ExpansionError::Unknown(format!("Fail to get response, reason : {:#?} ", err))
74+
})?),
75+
None => Err(tt::ExpansionError::Unknown("Empty result".into())),
11376
}
11477
}
11578
}
11679

117-
struct Task {
118-
req: Request,
119-
result_tx: Sender<Option<Response>>,
120-
}
121-
80+
#[derive(Debug)]
12281
struct Process {
12382
child: JodChild,
12483
}
@@ -133,7 +92,7 @@ impl Process {
13392
Ok(Process { child })
13493
}
13594

136-
fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
95+
fn stdio(&mut self) -> Option<(ChildStdin, BufReader<ChildStdout>)> {
13796
let stdin = self.child.stdin.take()?;
13897
let stdout = self.child.stdout.take()?;
13998
let read = BufReader::new(stdout);

crates/stdx/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub fn defer<F: FnOnce()>(f: F) -> impl Drop {
111111
}
112112

113113
#[cfg_attr(not(target_arch = "wasm32"), repr(transparent))]
114+
#[derive(Debug)]
114115
pub struct JodChild(pub std::process::Child);
115116

116117
impl ops::Deref for JodChild {

0 commit comments

Comments
 (0)