summaryrefslogtreecommitdiff
path: root/engine/src/work_queue.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/work_queue.rs')
-rw-r--r--engine/src/work_queue.rs36
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() {