mirror of
https://github.com/rust-mobile/android-activity.git
synced 2026-07-04 05:47:26 +00:00
native_activity: Only wait for state to update while main thread is running
We see that some Android callbacks like `onStart()` deadlock, specifically when returning out of the main thread before running any event loop (but likely also whenever terminating the event loop), because they don't check if the thread is still even running and are otherwise guaranteed receive an `activity_state` update or other state change to unblock themselves. This is a followup to [#94] which only concerned itself with a deadlock caused by a destructor not running because that very object was kept alive to poll on the `destroyed` field that destructor was supposed to set, but its new `thread_state` can be reused to disable these condvar waits when the "sending" thread has disappeared. Separately, that PR mentions `Activity` recreates because of configuration changes which isn't supported anyway because `Activity` is still wrongly assumed to be a global singleton. [#94]: https://togithub.com/rust-mobile/android-activity/pull/94
This commit is contained in:
committed by
Robert Bragg
parent
1652ebb229
commit
a97cf1ceae
@@ -447,7 +447,9 @@ impl WaitableNativeActivityState {
|
||||
|
||||
guard.pending_input_queue = input_queue;
|
||||
guard.write_cmd(AppCmd::InputQueueChanged);
|
||||
while guard.input_queue != guard.pending_input_queue {
|
||||
while guard.thread_state == NativeThreadState::Running
|
||||
&& guard.input_queue != guard.pending_input_queue
|
||||
{
|
||||
guard = self.cond.wait(guard).unwrap();
|
||||
}
|
||||
guard.pending_input_queue = ptr::null_mut();
|
||||
@@ -468,7 +470,9 @@ impl WaitableNativeActivityState {
|
||||
if guard.pending_window.is_some() {
|
||||
guard.write_cmd(AppCmd::InitWindow);
|
||||
}
|
||||
while guard.window != guard.pending_window {
|
||||
while guard.thread_state == NativeThreadState::Running
|
||||
&& guard.window != guard.pending_window
|
||||
{
|
||||
guard = self.cond.wait(guard).unwrap();
|
||||
}
|
||||
guard.pending_window = None;
|
||||
@@ -492,7 +496,7 @@ impl WaitableNativeActivityState {
|
||||
};
|
||||
guard.write_cmd(cmd);
|
||||
|
||||
while guard.activity_state != state {
|
||||
while guard.thread_state == NativeThreadState::Running && guard.activity_state != state {
|
||||
guard = self.cond.wait(guard).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -505,7 +509,7 @@ impl WaitableNativeActivityState {
|
||||
// this to be None
|
||||
debug_assert!(!guard.app_has_saved_state, "SaveState request clash");
|
||||
guard.write_cmd(AppCmd::SaveState);
|
||||
while !guard.app_has_saved_state {
|
||||
while guard.thread_state == NativeThreadState::Running && !guard.app_has_saved_state {
|
||||
guard = self.cond.wait(guard).unwrap();
|
||||
}
|
||||
guard.app_has_saved_state = false;
|
||||
@@ -560,7 +564,9 @@ impl WaitableNativeActivityState {
|
||||
pub fn notify_main_thread_stopped_running(&self) {
|
||||
let mut guard = self.mutex.lock().unwrap();
|
||||
guard.thread_state = NativeThreadState::Stopped;
|
||||
self.cond.notify_one();
|
||||
// Notify all waiters to unblock any Android callbacks that would otherwise be waiting
|
||||
// indefinitely for the now-stopped (!) main thread.
|
||||
self.cond.notify_all();
|
||||
}
|
||||
|
||||
pub unsafe fn pre_exec_cmd(
|
||||
|
||||
Reference in New Issue
Block a user