gpui(windows): Fix apps not quitting if they overwhelm the foreground thread with tasks (#43896)

Release Notes:

- N/A *or* Added/Fixed/Improved ...
This commit is contained in:
Lukas Wirth
2025-12-01 14:23:12 +00:00
committed by GitHub
parent 776c853756
commit de6855fa6e
+22 -19
View File
@@ -815,12 +815,14 @@ impl WindowsPlatformInner {
fn run_foreground_task(&self) -> Option<isize> {
const MAIN_TASK_TIMEOUT: u128 = 10;
let mut start = std::time::Instant::now();
loop {
loop {
let start = std::time::Instant::now();
'tasks: loop {
'timeout_loop: loop {
if start.elapsed().as_millis() >= MAIN_TASK_TIMEOUT {
// we spent our budget on gpui tasks, we likely have a lot of work queued so drain system events first
// before returning to main thread task work
log::debug!("foreground task timeout reached");
// we spent our budget on gpui tasks, we likely have a lot of work queued so drain system events first to stay responsive
// then quit out of foreground work to allow us to process other gpui events first before returning back to foreground task work
// if we don't we might not for example process window quit events
let mut msg = MSG::default();
let process_message = |msg: &_| {
if translate_accelerator(msg).is_none() {
@@ -831,39 +833,40 @@ impl WindowsPlatformInner {
let peek_msg = |msg: &mut _, msg_kind| unsafe {
PeekMessageW(msg, None, 0, 0, PM_REMOVE | msg_kind).as_bool()
};
// We process a paint at the start and end only to prevent getting stuck in a paint loop
// due to on going gpui animations
if peek_msg(&mut msg, PM_QS_PAINT) {
process_message(&msg);
}
while peek_msg(&mut msg, PM_QS_INPUT) {
process_message(&msg);
}
if peek_msg(&mut msg, PM_QS_PAINT) {
process_message(&msg);
// Allow the main loop to process other gpui events before going back into `run_foreground_task`
unsafe {
if let Err(_) = PostMessageW(
Some(self.dispatcher.platform_window_handle.as_raw()),
WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD,
WPARAM(self.validation_number),
LPARAM(0),
) {
self.dispatcher.wake_posted.store(false, Ordering::Release);
};
}
start = std::time::Instant::now();
break 'tasks;
}
match self.main_receiver.try_recv() {
Err(_) => break,
Err(_) => break 'timeout_loop,
Ok(runnable) => WindowsDispatcher::execute_runnable(runnable),
}
}
// Someone could enqueue a Runnable here. The flag is still true, so they will not PostMessage.
// We need to check for those Runnables after we clear the flag.
let dispatcher = self.dispatcher.clone();
dispatcher.wake_posted.store(false, Ordering::Release);
self.dispatcher.wake_posted.store(false, Ordering::Release);
match self.main_receiver.try_recv() {
Err(_) => break 'tasks,
Ok(runnable) => {
let _ = dispatcher.wake_posted.swap(true, Ordering::AcqRel);
self.dispatcher.wake_posted.store(true, Ordering::Release);
WindowsDispatcher::execute_runnable(runnable);
continue;
}
_ => {
break;
}
}
}