2
2
3
3
use super :: * ;
4
4
5
+ use std:: marker:: PhantomData ;
6
+
5
7
// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
6
8
use super :: client:: HandleStore ;
7
9
@@ -143,6 +145,41 @@ pub trait ExecutionStrategy {
143
145
) -> Buffer ;
144
146
}
145
147
148
+ pub struct MaybeCrossThread < P > {
149
+ cross_thread : bool ,
150
+ marker : PhantomData < P > ,
151
+ }
152
+
153
+ impl < P > MaybeCrossThread < P > {
154
+ pub const fn new ( cross_thread : bool ) -> Self {
155
+ MaybeCrossThread { cross_thread, marker : PhantomData }
156
+ }
157
+ }
158
+
159
+ impl < P > ExecutionStrategy for MaybeCrossThread < P >
160
+ where
161
+ P : MessagePipe < Buffer > + Send + ' static ,
162
+ {
163
+ fn run_bridge_and_client (
164
+ & self ,
165
+ dispatcher : & mut impl DispatcherTrait ,
166
+ input : Buffer ,
167
+ run_client : extern "C" fn ( BridgeConfig < ' _ > ) -> Buffer ,
168
+ force_show_panics : bool ,
169
+ ) -> Buffer {
170
+ if self . cross_thread {
171
+ <CrossThread < P > >:: new ( ) . run_bridge_and_client (
172
+ dispatcher,
173
+ input,
174
+ run_client,
175
+ force_show_panics,
176
+ )
177
+ } else {
178
+ SameThread . run_bridge_and_client ( dispatcher, input, run_client, force_show_panics)
179
+ }
180
+ }
181
+ }
182
+
146
183
pub struct SameThread ;
147
184
148
185
impl ExecutionStrategy for SameThread {
@@ -164,28 +201,31 @@ impl ExecutionStrategy for SameThread {
164
201
}
165
202
}
166
203
167
- // NOTE(eddyb) Two implementations are provided, the second one is a bit
168
- // faster but neither is anywhere near as fast as same-thread execution.
204
+ pub struct CrossThread < P > ( PhantomData < P > ) ;
169
205
170
- pub struct CrossThread1 ;
206
+ impl < P > CrossThread < P > {
207
+ pub const fn new ( ) -> Self {
208
+ CrossThread ( PhantomData )
209
+ }
210
+ }
171
211
172
- impl ExecutionStrategy for CrossThread1 {
212
+ impl < P > ExecutionStrategy for CrossThread < P >
213
+ where
214
+ P : MessagePipe < Buffer > + Send + ' static ,
215
+ {
173
216
fn run_bridge_and_client (
174
217
& self ,
175
218
dispatcher : & mut impl DispatcherTrait ,
176
219
input : Buffer ,
177
220
run_client : extern "C" fn ( BridgeConfig < ' _ > ) -> Buffer ,
178
221
force_show_panics : bool ,
179
222
) -> Buffer {
180
- use std:: sync:: mpsc:: channel;
181
-
182
- let ( req_tx, req_rx) = channel ( ) ;
183
- let ( res_tx, res_rx) = channel ( ) ;
223
+ let ( mut server, mut client) = P :: new ( ) ;
184
224
185
225
let join_handle = thread:: spawn ( move || {
186
- let mut dispatch = |buf| {
187
- req_tx . send ( buf ) . unwrap ( ) ;
188
- res_rx . recv ( ) . unwrap ( )
226
+ let mut dispatch = |b : Buffer | -> Buffer {
227
+ client . send ( b ) ;
228
+ client . recv ( ) . expect ( "server died while client waiting for reply" )
189
229
} ;
190
230
191
231
run_client ( BridgeConfig {
@@ -196,75 +236,27 @@ impl ExecutionStrategy for CrossThread1 {
196
236
} )
197
237
} ) ;
198
238
199
- for b in req_rx {
200
- res_tx . send ( dispatcher. dispatch ( b) ) . unwrap ( ) ;
239
+ while let Some ( b ) = server . recv ( ) {
240
+ server . send ( dispatcher. dispatch ( b) ) ;
201
241
}
202
242
203
243
join_handle. join ( ) . unwrap ( )
204
244
}
205
245
}
206
246
207
- pub struct CrossThread2 ;
247
+ /// A message pipe used for communicating between server and client threads.
248
+ pub trait MessagePipe < T > : Sized {
249
+ /// Create a new pair of endpoints for the message pipe.
250
+ fn new ( ) -> ( Self , Self ) ;
208
251
209
- impl ExecutionStrategy for CrossThread2 {
210
- fn run_bridge_and_client (
211
- & self ,
212
- dispatcher : & mut impl DispatcherTrait ,
213
- input : Buffer ,
214
- run_client : extern "C" fn ( BridgeConfig < ' _ > ) -> Buffer ,
215
- force_show_panics : bool ,
216
- ) -> Buffer {
217
- use std:: sync:: { Arc , Mutex } ;
218
-
219
- enum State < T > {
220
- Req ( T ) ,
221
- Res ( T ) ,
222
- }
223
-
224
- let mut state = Arc :: new ( Mutex :: new ( State :: Res ( Buffer :: new ( ) ) ) ) ;
225
-
226
- let server_thread = thread:: current ( ) ;
227
- let state2 = state. clone ( ) ;
228
- let join_handle = thread:: spawn ( move || {
229
- let mut dispatch = |b| {
230
- * state2. lock ( ) . unwrap ( ) = State :: Req ( b) ;
231
- server_thread. unpark ( ) ;
232
- loop {
233
- thread:: park ( ) ;
234
- if let State :: Res ( b) = & mut * state2. lock ( ) . unwrap ( ) {
235
- break b. take ( ) ;
236
- }
237
- }
238
- } ;
239
-
240
- let r = run_client ( BridgeConfig {
241
- input,
242
- dispatch : ( & mut dispatch) . into ( ) ,
243
- force_show_panics,
244
- _marker : marker:: PhantomData ,
245
- } ) ;
246
-
247
- // Wake up the server so it can exit the dispatch loop.
248
- drop ( state2) ;
249
- server_thread. unpark ( ) ;
250
-
251
- r
252
- } ) ;
253
-
254
- // Check whether `state2` was dropped, to know when to stop.
255
- while Arc :: get_mut ( & mut state) . is_none ( ) {
256
- thread:: park ( ) ;
257
- let mut b = match & mut * state. lock ( ) . unwrap ( ) {
258
- State :: Req ( b) => b. take ( ) ,
259
- _ => continue ,
260
- } ;
261
- b = dispatcher. dispatch ( b. take ( ) ) ;
262
- * state. lock ( ) . unwrap ( ) = State :: Res ( b) ;
263
- join_handle. thread ( ) . unpark ( ) ;
264
- }
252
+ /// Send a message to the other endpoint of this pipe.
253
+ fn send ( & mut self , value : T ) ;
265
254
266
- join_handle. join ( ) . unwrap ( )
267
- }
255
+ /// Receive a message from the other endpoint of this pipe.
256
+ ///
257
+ /// Returns `None` if the other end of the pipe has been destroyed, and no
258
+ /// message was received.
259
+ fn recv ( & mut self ) -> Option < T > ;
268
260
}
269
261
270
262
fn run_server <
0 commit comments