@@ -19,8 +19,12 @@ use nextest_runner::{
19
19
get_num_cpus, NextestConfig , NextestProfile , PreBuildPlatform , RetryPolicy , TestThreads ,
20
20
ToolConfigFile ,
21
21
} ,
22
+ double_spawn:: DoubleSpawnInfo ,
22
23
errors:: WriteTestListError ,
23
- list:: { BinaryList , OutputFormat , RustTestArtifact , SerializableFormat , TestList } ,
24
+ list:: {
25
+ BinaryList , OutputFormat , RustTestArtifact , SerializableFormat , TestExecuteContext ,
26
+ TestList ,
27
+ } ,
24
28
partition:: PartitionerBuilder ,
25
29
platform:: BuildPlatforms ,
26
30
reporter:: { FinalStatusLevel , StatusLevel , TestOutputDisplay , TestReporterBuilder } ,
@@ -53,15 +57,22 @@ pub struct CargoNextestApp {
53
57
impl CargoNextestApp {
54
58
/// Executes the app.
55
59
pub fn exec ( self , output_writer : & mut OutputWriter ) -> Result < i32 > {
56
- let NextestSubcommand :: Nextest ( app) = self . subcommand ;
57
- app. exec ( output_writer)
60
+ match self . subcommand {
61
+ NextestSubcommand :: Nextest ( app) => app. exec ( output_writer) ,
62
+ #[ cfg( unix) ]
63
+ NextestSubcommand :: DoubleSpawn ( opts) => opts. exec ( ) ,
64
+ }
58
65
}
59
66
}
60
67
61
68
#[ derive( Debug , Subcommand ) ]
62
69
enum NextestSubcommand {
63
70
/// A next-generation test runner for Rust. <https://nexte.st>
64
- Nextest ( AppOpts ) ,
71
+ Nextest ( Box < AppOpts > ) ,
72
+ /// Private command, used to double-spawn test processes.
73
+ #[ cfg( unix) ]
74
+ #[ command( name = nextest_runner:: double_spawn:: DoubleSpawnInfo :: SUBCOMMAND_NAME , hide = true ) ]
75
+ DoubleSpawn ( crate :: double_spawn:: DoubleSpawnOpts ) ,
65
76
}
66
77
67
78
#[ derive( Debug , Args ) ]
@@ -442,10 +453,10 @@ struct TestBuildFilter {
442
453
impl TestBuildFilter {
443
454
fn compute_test_list < ' g > (
444
455
& self ,
456
+ ctx : & TestExecuteContext < ' _ > ,
445
457
graph : & ' g PackageGraph ,
446
458
binary_list : Arc < BinaryList > ,
447
459
test_filter_builder : TestFilterBuilder ,
448
- runner : & TargetRunner ,
449
460
env : EnvironmentMap ,
450
461
reuse_build : & ReuseBuildInfo ,
451
462
) -> Result < TestList < ' g > > {
@@ -464,10 +475,10 @@ impl TestBuildFilter {
464
475
self . platform_filter . into ( ) ,
465
476
) ?;
466
477
TestList :: new (
478
+ ctx,
467
479
test_artifacts,
468
480
rust_build_meta,
469
481
& test_filter_builder,
470
- runner,
471
482
env,
472
483
// TODO: do we need to allow customizing this?
473
484
get_num_cpus ( ) ,
@@ -835,6 +846,7 @@ struct BaseApp {
835
846
config_opts : ConfigOpts ,
836
847
837
848
cargo_configs : CargoConfigs ,
849
+ double_spawn : OnceCell < DoubleSpawnInfo > ,
838
850
target_runner : OnceCell < TargetRunner > ,
839
851
}
840
852
@@ -918,10 +930,22 @@ impl BaseApp {
918
930
config_opts,
919
931
cargo_configs,
920
932
933
+ double_spawn : OnceCell :: new ( ) ,
921
934
target_runner : OnceCell :: new ( ) ,
922
935
} )
923
936
}
924
937
938
+ fn load_double_spawn ( & self ) -> & DoubleSpawnInfo {
939
+ self . double_spawn . get_or_init ( || {
940
+ if std:: env:: var ( "NEXTEST_EXPERIMENTAL_DOUBLE_SPAWN" ) == Ok ( "1" . to_owned ( ) ) {
941
+ log:: info!( "using experimental double-spawn method for test processes" ) ;
942
+ DoubleSpawnInfo :: enabled ( )
943
+ } else {
944
+ DoubleSpawnInfo :: disabled ( )
945
+ }
946
+ } )
947
+ }
948
+
925
949
fn load_runner ( & self , build_platforms : & BuildPlatforms ) -> & TargetRunner {
926
950
self . target_runner
927
951
. get_or_init ( || runner_for_target ( & self . cargo_configs , build_platforms) )
@@ -1039,16 +1063,16 @@ impl App {
1039
1063
1040
1064
fn build_test_list (
1041
1065
& self ,
1066
+ ctx : & TestExecuteContext < ' _ > ,
1042
1067
binary_list : Arc < BinaryList > ,
1043
1068
test_filter_builder : TestFilterBuilder ,
1044
- target_runner : & TargetRunner ,
1045
1069
) -> Result < TestList > {
1046
1070
let env = EnvironmentMap :: new ( & self . base . cargo_configs ) ;
1047
1071
self . build_filter . compute_test_list (
1072
+ ctx,
1048
1073
self . base . graph ( ) ,
1049
1074
binary_list,
1050
1075
test_filter_builder,
1051
- target_runner,
1052
1076
env,
1053
1077
& self . base . reuse_build ,
1054
1078
)
@@ -1101,11 +1125,16 @@ impl App {
1101
1125
writer. flush ( ) . map_err ( WriteTestListError :: Io ) ?;
1102
1126
}
1103
1127
ListType :: Full => {
1128
+ let double_spawn = self . base . load_double_spawn ( ) ;
1104
1129
let target_runner = self
1105
1130
. base
1106
1131
. load_runner ( & binary_list. rust_build_meta . build_platforms ( ) ?) ;
1107
- let test_list =
1108
- self . build_test_list ( binary_list, test_filter_builder, target_runner) ?;
1132
+ let ctx = TestExecuteContext {
1133
+ double_spawn,
1134
+ target_runner,
1135
+ } ;
1136
+
1137
+ let test_list = self . build_test_list ( & ctx, binary_list, test_filter_builder) ?;
1109
1138
1110
1139
let mut writer = output_writer. stdout_writer ( ) ;
1111
1140
test_list. write (
@@ -1138,9 +1167,14 @@ impl App {
1138
1167
1139
1168
let binary_list = self . base . build_binary_list ( ) ?;
1140
1169
let build_platforms = binary_list. rust_build_meta . build_platforms ( ) ?;
1170
+ let double_spawn = self . base . load_double_spawn ( ) ;
1141
1171
let target_runner = self . base . load_runner ( & build_platforms) ;
1172
+ let ctx = TestExecuteContext {
1173
+ double_spawn,
1174
+ target_runner,
1175
+ } ;
1142
1176
1143
- let test_list = self . build_test_list ( binary_list , test_filter_builder , target_runner ) ?;
1177
+ let test_list = self . build_test_list ( & ctx , binary_list , test_filter_builder ) ?;
1144
1178
1145
1179
let output = output_writer. reporter_output ( ) ;
1146
1180
let profile = profile. apply_build_platforms ( & build_platforms) ;
@@ -1162,8 +1196,13 @@ impl App {
1162
1196
}
1163
1197
} ;
1164
1198
1165
- let mut runner =
1166
- runner_builder. build ( & test_list, profile, handler, target_runner. clone ( ) ) ?;
1199
+ let mut runner = runner_builder. build (
1200
+ & test_list,
1201
+ profile,
1202
+ handler,
1203
+ double_spawn. clone ( ) ,
1204
+ target_runner. clone ( ) ,
1205
+ ) ?;
1167
1206
1168
1207
configure_handle_inheritance ( no_capture) ?;
1169
1208
let run_stats = runner. try_execute ( |event| {
0 commit comments