diff options
| author | HampusM <hampus@hampusmat.com> | 2026-06-23 22:28:46 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-06-23 22:28:46 +0200 |
| commit | 3531cf97cdbd188baf480ab614dc7feafee89dcf (patch) | |
| tree | d5b45cdcfd3c66aa52ad616d0a10219e0c262bcf /engine | |
| parent | 172bf5b905c6ab82e96f5ef8a14ff3bc9193f7ad (diff) | |
feat(engine): handle windowing thread errors in main thread
Diffstat (limited to 'engine')
| -rw-r--r-- | engine/src/windowing.rs | 104 |
1 files changed, 62 insertions, 42 deletions
diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index 0e2d1c3..a690ca4 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -3,10 +3,11 @@ use std::env::consts::EXE_SUFFIX; use std::hint::cold_path; use std::panic::catch_unwind; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Weak}; +use std::sync::{Arc, Weak, Mutex}; use std::thread::Builder as ThreadBuilder; use crossbeam_queue::ArrayQueue; +use ecs::error::Error as EcsError; use raw_window_handle::{DisplayHandle, HandleError, HasDisplayHandle, WindowHandle}; use rfd::{MessageButtons, MessageDialog, MessageLevel}; use winit::application::ApplicationHandler; @@ -166,7 +167,7 @@ fn update_stuff( mut mouse_buttons: Single<MouseButtons>, mut actions: Actions, entity_obtainer: EntityObtainer, -) +) -> Result<(), EcsError> { keyboard.make_key_states_previous(); mouse_buttons.make_states_previous(); @@ -190,6 +191,7 @@ fn update_stuff( ref mut display_handle, ref mut windows, ref thread_panicked, + ref shared_state, .. } = *context; @@ -297,8 +299,21 @@ fn update_stuff( if thread_panicked.load(Ordering::Relaxed) { cold_path(); - actions.stop(); + return Err("Windowing app thread panicked".into()); + } + + if shared_state.has_thread_err.load(Ordering::Relaxed) { + cold_path(); + + let mut err = shared_state.thread_err.try_lock().expect("Not possible"); + + let err = err.take().expect("Not possible"); + + return Err(err.into()); + } + + Ok(()) } fn handle_window_changed( @@ -442,17 +457,36 @@ impl Context ThreadBuilder::new() .name("windowing app".to_string()) .spawn(move || { - if catch_unwind(move || { - start_app( - message_from_app_queue_b, - message_to_app_queue_b, - shared_state_b, - ); - }) - .is_err() - { - thread_panicked_b.store(true, Ordering::Relaxed); - } + match catch_unwind(move || { + let mut app = App { + message_from_app_queue: message_from_app_queue_b, + message_to_app_queue: message_to_app_queue_b, + shared_state: shared_state_b, + windows: MapVec::default(), + }; + + let event_loop = match create_event_loop() { + Ok(event_loop) => event_loop, + Err(err) => { + return Err((app, AppThreadError::CreateEventLoop(err))); + } + }; + + event_loop.set_control_flow(EventLoopControlFlow::Poll); + + event_loop.run_app(&mut app).map_err(|err| (app, AppThreadError::StartEventLoop(err)))?; + + Ok(()) + }) { + Ok(Ok(())) => {}, + Ok(Err((app, err))) => { + *app.shared_state.thread_err.try_lock().expect("Not possible") = Some(err); + app.shared_state.has_thread_err.store(true, Ordering::Relaxed); + } + Err(_) => { + thread_panicked_b.store(true, Ordering::Relaxed); + } + }; }) .expect("Failed to create windowing thread"); @@ -475,34 +509,6 @@ impl Drop for Context } } -fn start_app( - message_from_app_queue_b: Arc<ArrayQueue<MessageFromApp>>, - message_to_app_queue_b: Arc<ArrayQueue<MessageToApp>>, - shared_state_b: Arc<SharedState>, -) -{ - let mut app = App { - message_from_app_queue: message_from_app_queue_b, - message_to_app_queue: message_to_app_queue_b, - shared_state: shared_state_b, - windows: MapVec::default(), - }; - - let event_loop = match create_event_loop() { - Ok(event_loop) => event_loop, - Err(err) => { - tracing::error!("Failed to create event loop: {err}"); - return; - } - }; - - event_loop.set_control_flow(EventLoopControlFlow::Poll); - - if let Err(err) = event_loop.run_app(&mut app) { - tracing::error!("Event loop error occurred: {err}"); - } -} - fn create_event_loop() -> Result<EventLoop<()>, EventLoopError> { let mut event_loop_builder = EventLoop::builder(); @@ -526,6 +532,16 @@ fn create_event_loop() -> Result<EventLoop<()>, EventLoopError> event_loop_builder.build() } +#[derive(Debug, thiserror::Error)] +enum AppThreadError +{ + #[error("Event loop creation failed")] + CreateEventLoop(#[source] winit::error::EventLoopError), + + #[error("Starting event loop failed")] + StartEventLoop(#[source] winit::error::EventLoopError), +} + #[derive(Debug)] enum MessageFromApp { @@ -552,6 +568,8 @@ struct SharedState absolute_mouse_pos: AtomicTwoF64, text_keys: ArrayQueue<char>, is_dropped: AtomicBool, + thread_err: Mutex<Option<AppThreadError>>, + has_thread_err: AtomicBool, } impl Default for SharedState @@ -563,6 +581,8 @@ impl Default for SharedState absolute_mouse_pos: AtomicTwoF64::new((0.0, 0.0)), text_keys: ArrayQueue::new(TEXT_KEY_QUEUE_SIZE), is_dropped: AtomicBool::new(false), + thread_err: Mutex::new(None), + has_thread_err: AtomicBool::new(false) } } } |
