diff --git a/.buildbot.sh b/.buildbot.sh index 5ec7d129c5633..18aa18489b568 100644 --- a/.buildbot.sh +++ b/.buildbot.sh @@ -7,4 +7,4 @@ set -e # Ensure the build fails if it uses excessive amounts of memory. ulimit -d $((1024 * 1024 * 8)) # 8 GiB -./x.py test --stage 1 --exclude rustdoc-json +./x.py test --stage 1 --exclude rustdoc-json --exclude debuginfo diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 45af9f68a0f6b..528fa2bc6d8e5 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -25,6 +25,7 @@ fn lang_start_internal( argc: isize, argv: *const *const u8, ) -> isize { + use crate::alloc::GcAllocator; use crate::panic; use crate::sys; use crate::sys_common; @@ -34,6 +35,14 @@ fn lang_start_internal( sys::init(); unsafe { + // Internally, this registers a SIGSEGV handler to compute the start and + // end bounds of the data segment. This means it *MUST* be called before + // rustc registers its own SIGSEGV stack overflow handler. + // + // Rust's stack overflow handler will unregister and return if there is + // no stack overflow, allowing the fault to "fall-through" to Boehm's + // handler next time. The is not true in the reverse case. + GcAllocator::init(); let main_guard = sys::thread::guard::init(); sys::stack_overflow::init(); diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index cda17eb4bd23c..f992d9a2da14d 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -277,7 +277,7 @@ pub mod guard { target_os = "netbsd", target_os = "l4re" ))] - unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + pub(crate) unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); #[cfg(target_os = "freebsd")] diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0d004a516f594..a92f307f4c136 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -148,6 +148,7 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; +use crate::alloc::GcAllocator; use crate::any::Any; use crate::cell::UnsafeCell; use crate::ffi::{CStr, CString}; @@ -464,6 +465,15 @@ impl Builder { imp::Thread::set_name(name); } + // SAFETY: Register the thread with libgc so that its stack can be scanned + // for garbage collection. + let stack_start = unsafe { imp::guard::get_stack_start().unwrap() }; + if stack_start != crate::ptr::null_mut() { + unsafe { + GcAllocator::register_thread(&stack_start as *const _ as *mut u8); + } + } + crate::io::set_output_capture(output_capture); // SAFETY: the stack guard passed is the one for the current thread. @@ -473,6 +483,12 @@ impl Builder { let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys_common::backtrace::__rust_begin_short_backtrace(f) })); + + // SAFETY: The thread has no more work to do, so can be unregisterd. + unsafe { + GcAllocator::unregister_thread(); + } + // SAFETY: `their_packet` as been built just above and moved by the // closure (it is an Arc<...>) and `my_packet` will be stored in the // same `JoinInner` as this closure meaning the mutation will be diff --git a/src/test/ui/threads-sendsync/thread_registration.rs b/src/test/ui/threads-sendsync/thread_registration.rs new file mode 100644 index 0000000000000..1e8f5a8daa0c4 --- /dev/null +++ b/src/test/ui/threads-sendsync/thread_registration.rs @@ -0,0 +1,15 @@ +// run-pass +// ignore-emscripten no threads support +#![feature(rustc_private)] + +use std::alloc::GcAllocator; +use std::thread; + +pub fn main() { + let res = thread::spawn(child).join().unwrap(); + assert!(res); +} + +fn child() -> bool { + GcAllocator::thread_registered() +}