about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2021-02-18 16:57:33 +0100
committerGitHub <noreply@github.com>2021-02-18 16:57:33 +0100
commit55ab2e38797ad1661ff4cfa95074a3d81636fde0 (patch)
treef0e24335cc00fb698c7aeab728539113bf1da127
parentcb2effd44e667d133e31ef334e30d10195218ce6 (diff)
parent43aed7441ee289c6228ecead91ee66245122b880 (diff)
downloadrust-55ab2e38797ad1661ff4cfa95074a3d81636fde0.tar.gz
rust-55ab2e38797ad1661ff4cfa95074a3d81636fde0.zip
Rollup merge of #81546 - hyd-dev:libtest-run-out-of-threads, r=Mark-Simulacrum
[libtest] Run the test synchronously when hitting thread limit

libtest currently panics if it hits the thread limit. This often results in spurious test failures (<code>thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }'</code> ... `error: test failed, to rerun pass '--lib'`). This PR makes it continue to run the test synchronously if it runs out of threads.

Closes #78165.

``@rustbot`` label: A-libtest T-libs
-rw-r--r--library/test/src/lib.rs13
-rw-r--r--src/test/run-make/libtest-thread-limit/Makefile7
-rw-r--r--src/test/run-make/libtest-thread-limit/test.rs16
3 files changed, 35 insertions, 1 deletions
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index c38a8c965be..ae38030d497 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -506,7 +506,18 @@ pub fn run_test(
         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
         if concurrency == Concurrent::Yes && supports_threads {
             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
-            Some(cfg.spawn(runtest).unwrap())
+            let mut runtest = Arc::new(Mutex::new(Some(runtest)));
+            let runtest2 = runtest.clone();
+            match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) {
+                Ok(handle) => Some(handle),
+                Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+                    // `ErrorKind::WouldBlock` means hitting the thread limit on some
+                    // platforms, so run the test synchronously here instead.
+                    Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
+                    None
+                }
+                Err(e) => panic!("failed to spawn thread to run test: {}", e),
+            }
         } else {
             runtest();
             None
diff --git a/src/test/run-make/libtest-thread-limit/Makefile b/src/test/run-make/libtest-thread-limit/Makefile
new file mode 100644
index 00000000000..29c1bc71d87
--- /dev/null
+++ b/src/test/run-make/libtest-thread-limit/Makefile
@@ -0,0 +1,7 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-linux
+
+all:
+	$(RUSTC) test.rs --test --target $(TARGET)
+	$(shell ulimit -p 0 && $(call RUN,test))
diff --git a/src/test/run-make/libtest-thread-limit/test.rs b/src/test/run-make/libtest-thread-limit/test.rs
new file mode 100644
index 00000000000..d899411a49e
--- /dev/null
+++ b/src/test/run-make/libtest-thread-limit/test.rs
@@ -0,0 +1,16 @@
+#![feature(once_cell)]
+
+use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}};
+
+static THREAD_ID: SyncOnceCell<ThreadId> = SyncOnceCell::new();
+
+#[test]
+fn spawn_thread_would_block() {
+    assert_eq!(Builder::new().spawn(|| unreachable!()).unwrap_err().kind(), ErrorKind::WouldBlock);
+    THREAD_ID.set(thread::current().id()).unwrap();
+}
+
+#[test]
+fn run_in_same_thread() {
+    assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id());
+}