summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-06-23 22:28:46 +0200
committerHampusM <hampus@hampusmat.com>2026-06-23 22:28:46 +0200
commit3531cf97cdbd188baf480ab614dc7feafee89dcf (patch)
treed5b45cdcfd3c66aa52ad616d0a10219e0c262bcf /engine
parent172bf5b905c6ab82e96f5ef8a14ff3bc9193f7ad (diff)
feat(engine): handle windowing thread errors in main thread
Diffstat (limited to 'engine')
-rw-r--r--engine/src/windowing.rs104
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)
}
}
}