Skip to content

Commit 5758c2d

Browse files
committed
Auto merge of #48575 - ishitatsuyuki:unix-no-thread, r=alexcrichton
rustc_driver: get rid of the extra thread **Do not rollup** We can alter the stack size afterwards on Unix. Having a separate thread causes poor debugging experience when interrupting with signals. I have to get the backtrace of the all thread, as the main thread is waiting to join doing nothing else. This patch allows me to just run `bt` to get the desired backtrace.
2 parents 20338a5 + 7db854b commit 5758c2d

File tree

10 files changed

+130
-18
lines changed

10 files changed

+130
-18
lines changed

src/librustc_driver/lib.rs

+49-8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#![feature(quote)]
2525
#![feature(rustc_diagnostic_macros)]
2626
#![feature(set_stdio)]
27+
#![feature(rustc_stack_internals)]
2728

2829
extern crate arena;
2930
extern crate getopts;
@@ -1467,16 +1468,56 @@ pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>>
14671468
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
14681469
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
14691470

1470-
let mut cfg = thread::Builder::new().name("rustc".to_string());
1471+
#[cfg(unix)]
1472+
let spawn_thread = unsafe {
1473+
// Fetch the current resource limits
1474+
let mut rlim = libc::rlimit {
1475+
rlim_cur: 0,
1476+
rlim_max: 0,
1477+
};
1478+
if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
1479+
let err = io::Error::last_os_error();
1480+
error!("in_rustc_thread: error calling getrlimit: {}", err);
1481+
true
1482+
} else if rlim.rlim_max < STACK_SIZE as libc::rlim_t {
1483+
true
1484+
} else {
1485+
std::rt::deinit_stack_guard();
1486+
rlim.rlim_cur = STACK_SIZE as libc::rlim_t;
1487+
if libc::setrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
1488+
let err = io::Error::last_os_error();
1489+
error!("in_rustc_thread: error calling setrlimit: {}", err);
1490+
std::rt::update_stack_guard();
1491+
true
1492+
} else {
1493+
std::rt::update_stack_guard();
1494+
false
1495+
}
1496+
}
1497+
};
14711498

1472-
// FIXME: Hacks on hacks. If the env is trying to override the stack size
1473-
// then *don't* set it explicitly.
1474-
if env::var_os("RUST_MIN_STACK").is_none() {
1475-
cfg = cfg.stack_size(STACK_SIZE);
1476-
}
1499+
// We set the stack size at link time. See src/rustc/rustc.rs.
1500+
#[cfg(windows)]
1501+
let spawn_thread = false;
1502+
1503+
#[cfg(not(any(windows,unix)))]
1504+
let spawn_thread = true;
14771505

1478-
let thread = cfg.spawn(f);
1479-
thread.unwrap().join()
1506+
// The or condition is added from backward compatibility.
1507+
if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() {
1508+
let mut cfg = thread::Builder::new().name("rustc".to_string());
1509+
1510+
// FIXME: Hacks on hacks. If the env is trying to override the stack size
1511+
// then *don't* set it explicitly.
1512+
if env::var_os("RUST_MIN_STACK").is_none() {
1513+
cfg = cfg.stack_size(STACK_SIZE);
1514+
}
1515+
1516+
let thread = cfg.spawn(f);
1517+
thread.unwrap().join()
1518+
} else {
1519+
Ok(f())
1520+
}
14801521
}
14811522

14821523
/// Get a list of extra command-line flags provided by the user, as strings.

src/libstd/rt.rs

+15
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,18 @@ fn lang_start<T: ::process::Termination + 'static>
7373
{
7474
lang_start_internal(&move || main().report(), argc, argv)
7575
}
76+
77+
/// Function used for reverting changes to the main stack before setrlimit().
78+
/// This is POSIX (non-Linux) specific and unlikely to be directly stabilized.
79+
#[unstable(feature = "rustc_stack_internals", issue = "0")]
80+
pub unsafe fn deinit_stack_guard() {
81+
::sys::thread::guard::deinit();
82+
}
83+
84+
/// Function used for resetting the main stack guard address after setrlimit().
85+
/// This is POSIX specific and unlikely to be directly stabilized.
86+
#[unstable(feature = "rustc_stack_internals", issue = "0")]
87+
pub unsafe fn update_stack_guard() {
88+
let main_guard = ::sys::thread::guard::init();
89+
::sys_common::thread_info::reset_guard(main_guard);
90+
}

src/libstd/sys/cloudabi/thread.rs

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ pub mod guard {
118118
pub unsafe fn init() -> Option<Guard> {
119119
None
120120
}
121+
pub unsafe fn deinit() {}
121122
}
122123

123124
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {

src/libstd/sys/redox/thread.rs

+1
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,5 @@ pub mod guard {
9191
pub type Guard = !;
9292
pub unsafe fn current() -> Option<Guard> { None }
9393
pub unsafe fn init() -> Option<Guard> { None }
94+
pub unsafe fn deinit() {}
9495
}

src/libstd/sys/unix/thread.rs

+38-10
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ pub mod guard {
209209
pub type Guard = Range<usize>;
210210
pub unsafe fn current() -> Option<Guard> { None }
211211
pub unsafe fn init() -> Option<Guard> { None }
212+
pub unsafe fn deinit() {}
212213
}
213214

214215

@@ -222,8 +223,8 @@ pub mod guard {
222223
#[cfg_attr(test, allow(dead_code))]
223224
pub mod guard {
224225
use libc;
225-
use libc::mmap;
226-
use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
226+
use libc::{mmap, mprotect};
227+
use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
227228
use ops::Range;
228229
use sys::os;
229230

@@ -284,10 +285,10 @@ pub mod guard {
284285
ret
285286
}
286287

287-
pub unsafe fn init() -> Option<Guard> {
288-
PAGE_SIZE = os::page_size();
289-
290-
let mut stackaddr = get_stack_start()?;
288+
// Precondition: PAGE_SIZE is initialized.
289+
unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
290+
assert!(PAGE_SIZE != 0);
291+
let stackaddr = get_stack_start()?;
291292

292293
// Ensure stackaddr is page aligned! A parent process might
293294
// have reset RLIMIT_STACK to be non-page aligned. The
@@ -296,10 +297,17 @@ pub mod guard {
296297
// page-aligned, calculate the fix such that stackaddr <
297298
// new_page_aligned_stackaddr < stackaddr + stacksize
298299
let remainder = (stackaddr as usize) % PAGE_SIZE;
299-
if remainder != 0 {
300-
stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder)
301-
as *mut libc::c_void;
302-
}
300+
Some(if remainder == 0 {
301+
stackaddr
302+
} else {
303+
((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void
304+
})
305+
}
306+
307+
pub unsafe fn init() -> Option<Guard> {
308+
PAGE_SIZE = os::page_size();
309+
310+
let stackaddr = get_stack_start_aligned()?;
303311

304312
if cfg!(target_os = "linux") {
305313
// Linux doesn't allocate the whole stack right away, and
@@ -336,6 +344,26 @@ pub mod guard {
336344
}
337345
}
338346

347+
pub unsafe fn deinit() {
348+
if !cfg!(target_os = "linux") {
349+
if let Some(stackaddr) = get_stack_start_aligned() {
350+
// Remove the protection on the guard page.
351+
// FIXME: we cannot unmap the page, because when we mmap()
352+
// above it may be already mapped by the OS, which we can't
353+
// detect from mmap()'s return value. If we unmap this page,
354+
// it will lead to failure growing stack size on platforms like
355+
// macOS. Instead, just restore the page to a writable state.
356+
// This ain't Linux, so we probably don't need to care about
357+
// execstack.
358+
let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE);
359+
360+
if result != 0 {
361+
panic!("unable to reset the guard page");
362+
}
363+
}
364+
}
365+
}
366+
339367
#[cfg(any(target_os = "macos",
340368
target_os = "bitrig",
341369
target_os = "openbsd",

src/libstd/sys/wasm/thread.rs

+1
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ pub mod guard {
4646
pub type Guard = !;
4747
pub unsafe fn current() -> Option<Guard> { None }
4848
pub unsafe fn init() -> Option<Guard> { None }
49+
pub unsafe fn deinit() {}
4950
}

src/libstd/sys/windows/thread.rs

+1
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,5 @@ pub mod guard {
9696
pub type Guard = !;
9797
pub unsafe fn current() -> Option<Guard> { None }
9898
pub unsafe fn init() -> Option<Guard> { None }
99+
pub unsafe fn deinit() {}
99100
}

src/libstd/sys_common/thread_info.rs

+4
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ pub fn set(stack_guard: Option<Guard>, thread: Thread) {
5050
thread,
5151
}));
5252
}
53+
54+
pub fn reset_guard(stack_guard: Option<Guard>) {
55+
THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard);
56+
}

src/rustc/rustc.rs

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
// except according to those terms.
1010

1111
#![feature(rustc_private)]
12+
#![feature(link_args)]
13+
14+
// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread
15+
// for the rationale.
16+
#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")]
17+
// We only build for msvc and gnu now, but we use a exhaustive condition here
18+
// so we can expect either the stack size to be set or the build fails.
19+
#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")]
20+
// Also, don't forget to set this for rustdoc.
21+
extern {}
1222

1323
extern crate rustc_driver;
1424

src/tools/rustdoc/main.rs

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(link_args)]
12+
// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread
13+
// for the rationale.
14+
#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")]
15+
// We only build for msvc and gnu now, but we use a exhaustive condition here
16+
// so we can expect either the stack size to be set or the build fails.
17+
#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")]
18+
// See src/rustc/rustc.rs for the corresponding rustc settings.
19+
extern {}
20+
1121
extern crate rustdoc;
1222

1323
fn main() { rustdoc::main() }

0 commit comments

Comments
 (0)