about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-02-04 14:20:36 +0000
committerGitHub <noreply@github.com>2025-02-04 14:20:36 +0000
commit21ddcbb836e4ee785cf64fdffa15c0f52503b5d4 (patch)
tree67d63bbcea3a2c9edb2e0ec5634cc9e5fccc5aff /src/tools
parent1ba7a38e4f95cd7d8666719140650ce551bd1753 (diff)
parent1ce2d7eacaca018a741bdf39b852438f38da91ba (diff)
downloadrust-21ddcbb836e4ee785cf64fdffa15c0f52503b5d4.tar.gz
rust-21ddcbb836e4ee785cf64fdffa15c0f52503b5d4.zip
Merge pull request #19093 from Veykril/push-lrvoookylnxp
Prevent panics from tearing down worker threads
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs6
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs21
2 files changed, 17 insertions, 10 deletions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
index 2bcd8505e81..c5de69bb9fc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
@@ -1,6 +1,8 @@
 //! A thin wrapper around [`stdx::thread::Pool`] which threads a sender through spawned jobs.
 //! It is used in [`crate::global_state::GlobalState`] throughout the main loop.
 
+use std::panic::UnwindSafe;
+
 use crossbeam_channel::Sender;
 use stdx::thread::{Pool, ThreadIntent};
 
@@ -18,7 +20,7 @@ impl<T> TaskPool<T> {
 
     pub(crate) fn spawn<F>(&mut self, intent: ThreadIntent, task: F)
     where
-        F: FnOnce() -> T + Send + 'static,
+        F: FnOnce() -> T + Send + UnwindSafe + 'static,
         T: Send + 'static,
     {
         self.pool.spawn(intent, {
@@ -29,7 +31,7 @@ impl<T> TaskPool<T> {
 
     pub(crate) fn spawn_with_sender<F>(&mut self, intent: ThreadIntent, task: F)
     where
-        F: FnOnce(Sender<T>) + Send + 'static,
+        F: FnOnce(Sender<T>) + Send + UnwindSafe + 'static,
         T: Send + 'static,
     {
         self.pool.spawn(intent, {
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
index 2ddd7da74c2..9acc1de922a 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
@@ -7,9 +7,12 @@
 //! The thread pool is implemented entirely using
 //! the threading utilities in [`crate::thread`].
 
-use std::sync::{
-    atomic::{AtomicUsize, Ordering},
-    Arc,
+use std::{
+    panic::{self, UnwindSafe},
+    sync::{
+        atomic::{AtomicUsize, Ordering},
+        Arc,
+    },
 };
 
 use crossbeam_channel::{Receiver, Sender};
@@ -25,13 +28,13 @@ pub struct Pool {
     // so that the channel is actually closed
     // before we join the worker threads!
     job_sender: Sender<Job>,
-    _handles: Vec<JoinHandle>,
+    _handles: Box<[JoinHandle]>,
     extant_tasks: Arc<AtomicUsize>,
 }
 
 struct Job {
     requested_intent: ThreadIntent,
-    f: Box<dyn FnOnce() + Send + 'static>,
+    f: Box<dyn FnOnce() + Send + UnwindSafe + 'static>,
 }
 
 impl Pool {
@@ -47,6 +50,7 @@ impl Pool {
             let handle = Builder::new(INITIAL_INTENT)
                 .stack_size(STACK_SIZE)
                 .name("Worker".into())
+                .allow_leak(true)
                 .spawn({
                     let extant_tasks = Arc::clone(&extant_tasks);
                     let job_receiver: Receiver<Job> = job_receiver.clone();
@@ -58,7 +62,8 @@ impl Pool {
                                 current_intent = job.requested_intent;
                             }
                             extant_tasks.fetch_add(1, Ordering::SeqCst);
-                            (job.f)();
+                            // discard the panic, we should've logged the backtrace already
+                            _ = panic::catch_unwind(job.f);
                             extant_tasks.fetch_sub(1, Ordering::SeqCst);
                         }
                     }
@@ -68,12 +73,12 @@ impl Pool {
             handles.push(handle);
         }
 
-        Pool { _handles: handles, extant_tasks, job_sender }
+        Pool { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
     }
 
     pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
     where
-        F: FnOnce() + Send + 'static,
+        F: FnOnce() + Send + UnwindSafe + 'static,
     {
         let f = Box::new(move || {
             if cfg!(debug_assertions) {