diff options
Diffstat (limited to 'engine/src/work_queue.rs')
| -rw-r--r-- | engine/src/work_queue.rs | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/engine/src/work_queue.rs b/engine/src/work_queue.rs index a2b7db9..494d2b5 100644 --- a/engine/src/work_queue.rs +++ b/engine/src/work_queue.rs @@ -1,5 +1,8 @@ +use std::borrow::Cow; use std::marker::PhantomData; +use std::panic::catch_unwind; use std::sync::mpsc::{channel as mpsc_channel, Sender as MpscSender}; +use std::sync::{Arc, OnceLock}; use std::thread::{Builder as ThreadBuilder, JoinHandle as ThreadJoinHandle}; pub struct Work<UserData: Send + Sync + 'static> @@ -12,6 +15,7 @@ pub struct Work<UserData: Send + Sync + 'static> pub struct WorkQueue<UserData: Send + Sync + 'static> { work_sender: MpscSender<Work<UserData>>, + thread_panic: Arc<OnceLock<Box<str>>>, _thread: ThreadJoinHandle<()>, _pd: PhantomData<UserData>, } @@ -22,15 +26,36 @@ impl<UserData: Send + Sync + 'static> WorkQueue<UserData> { let (work_sender, work_receiver) = mpsc_channel::<Work<UserData>>(); + let thread_panic = Arc::new(OnceLock::new()); + + let thread_panic_b = thread_panic.clone(); + Self { work_sender, + thread_panic: thread_panic, _thread: ThreadBuilder::new() .name(name.to_string()) .spawn(move || { - let work_receiver = work_receiver; + if let Err(panic_err) = catch_unwind(|| { + while let Ok(work) = work_receiver.recv() { + (work.func)(work.user_data); + } + }) { + let panic_message: Cow<'static, str> = + if let Some(panic_message) = + panic_err.downcast_ref::<&'static str>() + { + (*panic_message).into() + } else if let Some(panic_message) = + panic_err.downcast_ref::<String>() + { + panic_message.clone().into() + } else { + "(unknown panic payload type)".into() + }; - while let Ok(work) = work_receiver.recv() { - (work.func)(work.user_data); + let _ = thread_panic_b + .set(panic_message.into_owned().into_boxed_str()); } }) .expect("Failed to create work queue thread"), @@ -38,6 +63,11 @@ impl<UserData: Send + Sync + 'static> WorkQueue<UserData> } } + pub fn get_thread_panic(&self) -> Option<&str> + { + self.thread_panic.get().map(|thread_panic| &**thread_panic) + } + pub fn add_work(&self, work: Work<UserData>) { if self.work_sender.send(work).is_err() { |
