@@ -44,6 +44,7 @@ static TEST: AtomicUsize = AtomicUsize::new(0);
44
44
struct Config {
45
45
verbose : bool ,
46
46
sequential : bool ,
47
+ batch : bool ,
47
48
bind : SocketAddr ,
48
49
}
49
50
@@ -52,6 +53,7 @@ impl Config {
52
53
Config {
53
54
verbose : false ,
54
55
sequential : false ,
56
+ batch : false ,
55
57
bind : if cfg ! ( target_os = "android" ) || cfg ! ( windows) {
56
58
( [ 0 , 0 , 0 , 0 ] , 12345 ) . into ( )
57
59
} else {
@@ -73,6 +75,7 @@ impl Config {
73
75
}
74
76
"--bind" => next_is_bind = true ,
75
77
"--sequential" => config. sequential = true ,
78
+ "--batch" => config. batch = true ,
76
79
"--verbose" | "-v" => config. verbose = true ,
77
80
"--help" | "-h" => {
78
81
show_help ( ) ;
@@ -98,6 +101,7 @@ fn show_help() {
98
101
OPTIONS:
99
102
--bind <IP>:<PORT> Specify IP address and port to listen for requests, e.g. "0.0.0.0:12345"
100
103
--sequential Run only one test at a time
104
+ --batch Send stdout and stderr in batch instead of streaming
101
105
-v, --verbose Show status messages
102
106
-h, --help Show this help screen
103
107
"# ,
@@ -268,22 +272,30 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf
268
272
// Some tests assume RUST_TEST_TMPDIR exists
269
273
cmd. env ( "RUST_TEST_TMPDIR" , tmp. to_owned ( ) ) ;
270
274
271
- // Spawn the child and ferry over stdout/stderr to the socket in a framed
272
- // fashion (poor man's style)
273
- let mut child =
274
- t ! ( cmd. stdin( Stdio :: null( ) ) . stdout( Stdio :: piped( ) ) . stderr( Stdio :: piped( ) ) . spawn( ) ) ;
275
- drop ( lock) ;
276
- let mut stdout = child. stdout . take ( ) . unwrap ( ) ;
277
- let mut stderr = child. stderr . take ( ) . unwrap ( ) ;
278
275
let socket = Arc :: new ( Mutex :: new ( reader. into_inner ( ) ) ) ;
279
- let socket2 = socket. clone ( ) ;
280
- let thread = thread:: spawn ( move || my_copy ( & mut stdout, 0 , & * socket2) ) ;
281
- my_copy ( & mut stderr, 1 , & * socket) ;
282
- thread. join ( ) . unwrap ( ) ;
283
276
284
- // Finally send over the exit status.
285
- let status = t ! ( child. wait( ) ) ;
277
+ let status = if config. batch {
278
+ let child =
279
+ t ! ( cmd. stdin( Stdio :: null( ) ) . stdout( Stdio :: piped( ) ) . stderr( Stdio :: piped( ) ) . output( ) ) ;
280
+ batch_copy ( & child. stdout , 0 , & * socket) ;
281
+ batch_copy ( & child. stderr , 1 , & * socket) ;
282
+ child. status
283
+ } else {
284
+ // Spawn the child and ferry over stdout/stderr to the socket in a framed
285
+ // fashion (poor man's style)
286
+ let mut child =
287
+ t ! ( cmd. stdin( Stdio :: null( ) ) . stdout( Stdio :: piped( ) ) . stderr( Stdio :: piped( ) ) . spawn( ) ) ;
288
+ drop ( lock) ;
289
+ let mut stdout = child. stdout . take ( ) . unwrap ( ) ;
290
+ let mut stderr = child. stderr . take ( ) . unwrap ( ) ;
291
+ let socket2 = socket. clone ( ) ;
292
+ let thread = thread:: spawn ( move || my_copy ( & mut stdout, 0 , & * socket2) ) ;
293
+ my_copy ( & mut stderr, 1 , & * socket) ;
294
+ thread. join ( ) . unwrap ( ) ;
295
+ t ! ( child. wait( ) )
296
+ } ;
286
297
298
+ // Finally send over the exit status.
287
299
let ( which, code) = get_status_code ( & status) ;
288
300
289
301
t ! ( socket. lock( ) . unwrap( ) . write_all( & [
@@ -356,6 +368,17 @@ fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex<dyn Write>) {
356
368
}
357
369
}
358
370
371
+ fn batch_copy ( buf : & [ u8 ] , which : u8 , dst : & Mutex < dyn Write > ) {
372
+ let n = buf. len ( ) ;
373
+ let mut dst = dst. lock ( ) . unwrap ( ) ;
374
+ t ! ( dst. write_all( & [ which, ( n >> 24 ) as u8 , ( n >> 16 ) as u8 , ( n >> 8 ) as u8 , ( n >> 0 ) as u8 , ] ) ) ;
375
+ if n > 0 {
376
+ t ! ( dst. write_all( buf) ) ;
377
+ // Marking buf finished
378
+ t ! ( dst. write_all( & [ which, 0 , 0 , 0 , 0 , ] ) ) ;
379
+ }
380
+ }
381
+
359
382
fn read_u32 ( r : & mut dyn Read ) -> u32 {
360
383
let mut len = [ 0 ; 4 ] ;
361
384
t ! ( r. read_exact( & mut len) ) ;
0 commit comments