Skip to content

Commit 5301407

Browse files
committed
Avoid an unnecessary thread creation at rustdoc startup.
rustdoc's `main()` immediately spawns a thread, M, with a large stack (16MiB or 32MiB) on which it runs `main_args()`. `main_args()` does a small amount of options processing and then calls `setup_callbacks_and_run_in_default_thread_pool_with_globals()`, which spawns it own thread, and M is not used further. So, thread M seems unnecessary. However, it does serve a purpose: if the options processing in `main_args()` panics, that panic is caught when M is joined. So M can't simply be removed. However, `main_options()`, which is called by `main_args()`, has a `catch_fatal_errors()` call within it. We can move that call to `main()` and change it to the very similar `catch_with_exit_code()`. With that in place, M can be removed, and panics from options processing will still be caught appropriately. Even better, this makes rustdoc's `main()` match rustc's `main()`, which also uses `catch_with_exit_code()`. (Also note that the use of a 16MiB/32MiB stack was eliminated from rustc in rust-lang#55617.)
1 parent 8244b1b commit 5301407

File tree

1 file changed

+46
-55
lines changed

1 file changed

+46
-55
lines changed

src/librustdoc/lib.rs

+46-55
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ extern crate log;
4747

4848
use std::default::Default;
4949
use std::env;
50-
use std::panic;
5150
use std::process;
5251

52+
use rustc_errors::ErrorReported;
5353
use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
5454
use rustc_session::getopts;
5555
use rustc_session::{early_error, early_warn};
@@ -82,22 +82,14 @@ struct Output {
8282
}
8383

8484
pub fn main() {
85-
let thread_stack_size: usize = if cfg!(target_os = "haiku") {
86-
16_000_000 // 16MB on Haiku
87-
} else {
88-
32_000_000 // 32MB on other platforms
89-
};
9085
rustc_driver::set_sigpipe_handler();
9186
rustc_driver::install_ice_hook();
9287
rustc_driver::init_env_logger("RUSTDOC_LOG");
93-
94-
let res = std::thread::Builder::new()
95-
.stack_size(thread_stack_size)
96-
.spawn(move || get_args().map(|args| main_args(&args)).unwrap_or(1))
97-
.unwrap()
98-
.join()
99-
.unwrap_or(rustc_driver::EXIT_FAILURE);
100-
process::exit(res);
88+
let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
89+
Some(args) => main_args(&args),
90+
_ => Err(ErrorReported),
91+
});
92+
process::exit(exit_code);
10193
}
10294

10395
fn get_args() -> Option<Vec<String>> {
@@ -418,7 +410,10 @@ fn usage(argv0: &str) {
418410
println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
419411
}
420412

421-
fn main_args(args: &[String]) -> i32 {
413+
/// A result type used by several functions under `main()`.
414+
type MainResult = Result<(), ErrorReported>;
415+
416+
fn main_args(args: &[String]) -> MainResult {
422417
let mut options = getopts::Options::new();
423418
for option in opts() {
424419
(option.apply)(&mut options);
@@ -429,24 +424,27 @@ fn main_args(args: &[String]) -> i32 {
429424
early_error(ErrorOutputType::default(), &err.to_string());
430425
}
431426
};
427+
428+
// Note that we discard any distinction between different non-zero exit
429+
// codes from `from_matches` here.
432430
let options = match config::Options::from_matches(&matches) {
433431
Ok(opts) => opts,
434-
Err(code) => return code,
432+
Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) },
435433
};
436434
rustc_interface::interface::setup_callbacks_and_run_in_default_thread_pool_with_globals(
437435
options.edition,
438436
move || main_options(options),
439437
)
440438
}
441439

442-
fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> i32 {
440+
fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult {
443441
match res {
444-
Ok(()) => 0,
442+
Ok(()) => Ok(()),
445443
Err(err) => {
446444
if !err.is_empty() {
447445
diag.struct_err(&err).emit();
448446
}
449-
1
447+
Err(ErrorReported)
450448
}
451449
}
452450
}
@@ -457,9 +455,9 @@ fn run_renderer<T: formats::FormatRenderer>(
457455
render_info: config::RenderInfo,
458456
diag: &rustc_errors::Handler,
459457
edition: rustc_span::edition::Edition,
460-
) -> i32 {
458+
) -> MainResult {
461459
match formats::run_format::<T>(krate, renderopts, render_info, &diag, edition) {
462-
Ok(_) => rustc_driver::EXIT_SUCCESS,
460+
Ok(_) => Ok(()),
463461
Err(e) => {
464462
let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error));
465463
let file = e.file.display().to_string();
@@ -468,12 +466,12 @@ fn run_renderer<T: formats::FormatRenderer>(
468466
} else {
469467
msg.note(&format!("failed to create or modify \"{}\"", file)).emit()
470468
}
471-
rustc_driver::EXIT_FAILURE
469+
Err(ErrorReported)
472470
}
473471
}
474472
}
475473

476-
fn main_options(options: config::Options) -> i32 {
474+
fn main_options(options: config::Options) -> MainResult {
477475
let diag = core::new_handler(options.error_format, None, &options.debugging_options);
478476

479477
match (options.should_test, options.markdown_input()) {
@@ -500,44 +498,37 @@ fn main_options(options: config::Options) -> i32 {
500498
// compiler all the way through the analysis passes. The rustdoc output is
501499
// then generated from the cleaned AST of the crate. This runs all the
502500
// plug/cleaning passes.
503-
let result = rustc_driver::catch_fatal_errors(move || {
504-
let crate_name = options.crate_name.clone();
505-
let crate_version = options.crate_version.clone();
506-
let output_format = options.output_format;
507-
let (mut krate, renderinfo, renderopts) = core::run_core(options);
501+
let crate_name = options.crate_name.clone();
502+
let crate_version = options.crate_version.clone();
503+
let output_format = options.output_format;
504+
let (mut krate, renderinfo, renderopts) = core::run_core(options);
508505

509-
info!("finished with rustc");
506+
info!("finished with rustc");
510507

511-
if let Some(name) = crate_name {
512-
krate.name = name
513-
}
508+
if let Some(name) = crate_name {
509+
krate.name = name
510+
}
514511

515-
krate.version = crate_version;
512+
krate.version = crate_version;
516513

517-
let out = Output { krate, renderinfo, renderopts };
514+
let out = Output { krate, renderinfo, renderopts };
518515

519-
if show_coverage {
520-
// if we ran coverage, bail early, we don't need to also generate docs at this point
521-
// (also we didn't load in any of the useful passes)
522-
return rustc_driver::EXIT_SUCCESS;
523-
}
516+
if show_coverage {
517+
// if we ran coverage, bail early, we don't need to also generate docs at this point
518+
// (also we didn't load in any of the useful passes)
519+
return Ok(());
520+
}
524521

525-
let Output { krate, renderinfo, renderopts } = out;
526-
info!("going to format");
527-
let (error_format, edition, debugging_options) = diag_opts;
528-
let diag = core::new_handler(error_format, None, &debugging_options);
529-
match output_format {
530-
None | Some(config::OutputFormat::Html) => {
531-
run_renderer::<html::render::Context>(krate, renderopts, renderinfo, &diag, edition)
532-
}
533-
Some(config::OutputFormat::Json) => {
534-
run_renderer::<json::JsonRenderer>(krate, renderopts, renderinfo, &diag, edition)
535-
}
522+
let Output { krate, renderinfo, renderopts } = out;
523+
info!("going to format");
524+
let (error_format, edition, debugging_options) = diag_opts;
525+
let diag = core::new_handler(error_format, None, &debugging_options);
526+
match output_format {
527+
None | Some(config::OutputFormat::Html) => {
528+
run_renderer::<html::render::Context>(krate, renderopts, renderinfo, &diag, edition)
529+
}
530+
Some(config::OutputFormat::Json) => {
531+
run_renderer::<json::JsonRenderer>(krate, renderopts, renderinfo, &diag, edition)
536532
}
537-
});
538-
539-
match result {
540-
Ok(output) => output,
541-
Err(_) => panic::resume_unwind(Box::new(rustc_errors::FatalErrorMarker)),
542533
}
543534
}

0 commit comments

Comments
 (0)