Skip to content

Commit 19640ee

Browse files
committed
proc_macro/bridge: rely on client-thread server-side TLS in ExecutionStrategy.
1 parent f38555c commit 19640ee

File tree

1 file changed

+71
-55
lines changed

1 file changed

+71
-55
lines changed

library/proc_macro/src/bridge/server.rs

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ macro_rules! define_dispatcher_impl {
128128
}
129129
with_api!(Self, self_, define_dispatcher_impl);
130130

131+
// FIXME(eddyb) a trait alias of `FnMut(Buffer<u8>) -> Buffer<u8>` would allow
132+
// replacing the non-dynamic mentions of that trait, as well.
133+
pub type DynDispatch<'a> = &'a mut dyn FnMut(Buffer<u8>) -> Buffer<u8>;
134+
131135
pub trait ExecutionStrategy {
132136
fn run_bridge_and_client<D: Copy + Send + 'static>(
133137
&self,
@@ -136,31 +140,69 @@ pub trait ExecutionStrategy {
136140
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
137141
client_data: D,
138142
force_show_panics: bool,
143+
) -> Buffer<u8> {
144+
enum OptionDynDispatchL {}
145+
146+
impl<'a> scoped_cell::ApplyL<'a> for OptionDynDispatchL {
147+
type Out = Option<DynDispatch<'a>>;
148+
}
149+
150+
thread_local! {
151+
/// Dispatch callback held in server TLS, and using server ABI, but
152+
/// on the client thread (which can differ from the server thread).
153+
//
154+
// FIXME(eddyb) how redundant is this with the (also) thread-local
155+
// client-side `BridgeState`? Some of that indirection can probably
156+
// be removed, as long as concerns around further isolation methods
157+
// (IPC and/or wasm) are considered.
158+
static CLIENT_THREAD_DISPATCH: scoped_cell::ScopedCell<OptionDynDispatchL> =
159+
scoped_cell::ScopedCell::new(None);
160+
}
161+
162+
self.cross_thread_dispatch(
163+
|b| dispatcher.dispatch(b),
164+
move |client_thread_dispatch| {
165+
CLIENT_THREAD_DISPATCH.with(|dispatch_slot| {
166+
dispatch_slot.set(Some(client_thread_dispatch), || {
167+
let mut dispatch = |b| {
168+
CLIENT_THREAD_DISPATCH.with(|dispatch_slot| {
169+
dispatch_slot.replace(None, |mut client_thread_dispatch| {
170+
client_thread_dispatch.as_mut().unwrap()(b)
171+
})
172+
})
173+
};
174+
175+
run_client(
176+
Bridge {
177+
cached_buffer: input,
178+
dispatch: (&mut dispatch).into(),
179+
force_show_panics,
180+
_marker: marker::PhantomData,
181+
},
182+
client_data,
183+
)
184+
})
185+
})
186+
},
187+
)
188+
}
189+
190+
fn cross_thread_dispatch(
191+
&self,
192+
server_thread_dispatch: impl FnMut(Buffer<u8>) -> Buffer<u8>,
193+
with_client_thread_dispatch: impl FnOnce(DynDispatch<'_>) -> Buffer<u8> + Send + 'static,
139194
) -> Buffer<u8>;
140195
}
141196

142197
pub struct SameThread;
143198

144199
impl ExecutionStrategy for SameThread {
145-
fn run_bridge_and_client<D: Copy + Send + 'static>(
200+
fn cross_thread_dispatch(
146201
&self,
147-
dispatcher: &mut impl DispatcherTrait,
148-
input: Buffer<u8>,
149-
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
150-
client_data: D,
151-
force_show_panics: bool,
202+
mut server_thread_dispatch: impl FnMut(Buffer<u8>) -> Buffer<u8>,
203+
with_client_thread_dispatch: impl FnOnce(DynDispatch<'_>) -> Buffer<u8> + Send + 'static,
152204
) -> Buffer<u8> {
153-
let mut dispatch = |b| dispatcher.dispatch(b);
154-
155-
run_client(
156-
Bridge {
157-
cached_buffer: input,
158-
dispatch: (&mut dispatch).into(),
159-
force_show_panics,
160-
_marker: marker::PhantomData,
161-
},
162-
client_data,
163-
)
205+
with_client_thread_dispatch(&mut server_thread_dispatch)
164206
}
165207
}
166208

@@ -170,38 +212,25 @@ impl ExecutionStrategy for SameThread {
170212
pub struct CrossThread1;
171213

172214
impl ExecutionStrategy for CrossThread1 {
173-
fn run_bridge_and_client<D: Copy + Send + 'static>(
215+
fn cross_thread_dispatch(
174216
&self,
175-
dispatcher: &mut impl DispatcherTrait,
176-
input: Buffer<u8>,
177-
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
178-
client_data: D,
179-
force_show_panics: bool,
217+
mut server_thread_dispatch: impl FnMut(Buffer<u8>) -> Buffer<u8>,
218+
with_client_thread_dispatch: impl FnOnce(DynDispatch<'_>) -> Buffer<u8> + Send + 'static,
180219
) -> Buffer<u8> {
181220
use std::sync::mpsc::channel;
182221

183222
let (req_tx, req_rx) = channel();
184223
let (res_tx, res_rx) = channel();
185224

186225
let join_handle = thread::spawn(move || {
187-
let mut dispatch = |b| {
226+
with_client_thread_dispatch(&mut |b| {
188227
req_tx.send(b).unwrap();
189228
res_rx.recv().unwrap()
190-
};
191-
192-
run_client(
193-
Bridge {
194-
cached_buffer: input,
195-
dispatch: (&mut dispatch).into(),
196-
force_show_panics,
197-
_marker: marker::PhantomData,
198-
},
199-
client_data,
200-
)
229+
})
201230
});
202231

203232
for b in req_rx {
204-
res_tx.send(dispatcher.dispatch(b)).unwrap();
233+
res_tx.send(server_thread_dispatch(b)).unwrap();
205234
}
206235

207236
join_handle.join().unwrap()
@@ -211,13 +240,10 @@ impl ExecutionStrategy for CrossThread1 {
211240
pub struct CrossThread2;
212241

213242
impl ExecutionStrategy for CrossThread2 {
214-
fn run_bridge_and_client<D: Copy + Send + 'static>(
243+
fn cross_thread_dispatch(
215244
&self,
216-
dispatcher: &mut impl DispatcherTrait,
217-
input: Buffer<u8>,
218-
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
219-
client_data: D,
220-
force_show_panics: bool,
245+
mut server_thread_dispatch: impl FnMut(Buffer<u8>) -> Buffer<u8>,
246+
with_client_thread_dispatch: impl FnOnce(DynDispatch<'_>) -> Buffer<u8> + Send + 'static,
221247
) -> Buffer<u8> {
222248
use std::sync::{Arc, Mutex};
223249

@@ -231,7 +257,7 @@ impl ExecutionStrategy for CrossThread2 {
231257
let server_thread = thread::current();
232258
let state2 = state.clone();
233259
let join_handle = thread::spawn(move || {
234-
let mut dispatch = |b| {
260+
let r = with_client_thread_dispatch(&mut |b| {
235261
*state2.lock().unwrap() = State::Req(b);
236262
server_thread.unpark();
237263
loop {
@@ -240,17 +266,7 @@ impl ExecutionStrategy for CrossThread2 {
240266
break b.take();
241267
}
242268
}
243-
};
244-
245-
let r = run_client(
246-
Bridge {
247-
cached_buffer: input,
248-
dispatch: (&mut dispatch).into(),
249-
force_show_panics,
250-
_marker: marker::PhantomData,
251-
},
252-
client_data,
253-
);
269+
});
254270

255271
// Wake up the server so it can exit the dispatch loop.
256272
drop(state2);
@@ -266,7 +282,7 @@ impl ExecutionStrategy for CrossThread2 {
266282
State::Req(b) => b.take(),
267283
_ => continue,
268284
};
269-
b = dispatcher.dispatch(b.take());
285+
b = server_thread_dispatch(b.take());
270286
*state.lock().unwrap() = State::Res(b);
271287
join_handle.thread().unpark();
272288
}

0 commit comments

Comments
 (0)