@@ -128,6 +128,10 @@ macro_rules! define_dispatcher_impl {
128
128
}
129
129
with_api ! ( Self , self_, define_dispatcher_impl) ;
130
130
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
+
131
135
pub trait ExecutionStrategy {
132
136
fn run_bridge_and_client < D : Copy + Send + ' static > (
133
137
& self ,
@@ -136,31 +140,69 @@ pub trait ExecutionStrategy {
136
140
run_client : extern "C" fn ( Bridge < ' _ > , D ) -> Buffer < u8 > ,
137
141
client_data : D ,
138
142
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 ,
139
194
) -> Buffer < u8 > ;
140
195
}
141
196
142
197
pub struct SameThread ;
143
198
144
199
impl ExecutionStrategy for SameThread {
145
- fn run_bridge_and_client < D : Copy + Send + ' static > (
200
+ fn cross_thread_dispatch (
146
201
& 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 ,
152
204
) -> 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)
164
206
}
165
207
}
166
208
@@ -170,38 +212,25 @@ impl ExecutionStrategy for SameThread {
170
212
pub struct CrossThread1 ;
171
213
172
214
impl ExecutionStrategy for CrossThread1 {
173
- fn run_bridge_and_client < D : Copy + Send + ' static > (
215
+ fn cross_thread_dispatch (
174
216
& 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 ,
180
219
) -> Buffer < u8 > {
181
220
use std:: sync:: mpsc:: channel;
182
221
183
222
let ( req_tx, req_rx) = channel ( ) ;
184
223
let ( res_tx, res_rx) = channel ( ) ;
185
224
186
225
let join_handle = thread:: spawn ( move || {
187
- let mut dispatch = |b| {
226
+ with_client_thread_dispatch ( & mut |b| {
188
227
req_tx. send ( b) . unwrap ( ) ;
189
228
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
+ } )
201
230
} ) ;
202
231
203
232
for b in req_rx {
204
- res_tx. send ( dispatcher . dispatch ( b) ) . unwrap ( ) ;
233
+ res_tx. send ( server_thread_dispatch ( b) ) . unwrap ( ) ;
205
234
}
206
235
207
236
join_handle. join ( ) . unwrap ( )
@@ -211,13 +240,10 @@ impl ExecutionStrategy for CrossThread1 {
211
240
pub struct CrossThread2 ;
212
241
213
242
impl ExecutionStrategy for CrossThread2 {
214
- fn run_bridge_and_client < D : Copy + Send + ' static > (
243
+ fn cross_thread_dispatch (
215
244
& 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 ,
221
247
) -> Buffer < u8 > {
222
248
use std:: sync:: { Arc , Mutex } ;
223
249
@@ -231,7 +257,7 @@ impl ExecutionStrategy for CrossThread2 {
231
257
let server_thread = thread:: current ( ) ;
232
258
let state2 = state. clone ( ) ;
233
259
let join_handle = thread:: spawn ( move || {
234
- let mut dispatch = |b| {
260
+ let r = with_client_thread_dispatch ( & mut |b| {
235
261
* state2. lock ( ) . unwrap ( ) = State :: Req ( b) ;
236
262
server_thread. unpark ( ) ;
237
263
loop {
@@ -240,17 +266,7 @@ impl ExecutionStrategy for CrossThread2 {
240
266
break b. take ( ) ;
241
267
}
242
268
}
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
+ } ) ;
254
270
255
271
// Wake up the server so it can exit the dispatch loop.
256
272
drop ( state2) ;
@@ -266,7 +282,7 @@ impl ExecutionStrategy for CrossThread2 {
266
282
State :: Req ( b) => b. take ( ) ,
267
283
_ => continue ,
268
284
} ;
269
- b = dispatcher . dispatch ( b. take ( ) ) ;
285
+ b = server_thread_dispatch ( b. take ( ) ) ;
270
286
* state. lock ( ) . unwrap ( ) = State :: Res ( b) ;
271
287
join_handle. thread ( ) . unpark ( ) ;
272
288
}
0 commit comments