From 1ce2d7eacaca018a741bdf39b852438f38da91ba Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 4 Feb 2025 14:43:01 +0100 Subject: [PATCH] Prevent panics from tearing down worker threads --- .../crates/rust-analyzer/src/task_pool.rs | 6 ++++-- .../crates/stdx/src/thread/pool.rs | 21 ++++++++++++------- 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 2bcd8505e8100..c5de69bb9fc83 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 TaskPool { pub(crate) fn spawn(&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 TaskPool { pub(crate) fn spawn_with_sender(&mut self, intent: ThreadIntent, task: F) where - F: FnOnce(Sender) + Send + 'static, + F: FnOnce(Sender) + 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 2ddd7da74c291..9acc1de922af9 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, - _handles: Vec, + _handles: Box<[JoinHandle]>, extant_tasks: Arc, } struct Job { requested_intent: ThreadIntent, - f: Box, + f: Box, } 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_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(&self, intent: ThreadIntent, f: F) where - F: FnOnce() + Send + 'static, + F: FnOnce() + Send + UnwindSafe + 'static, { let f = Box::new(move || { if cfg!(debug_assertions) {