Skip to content

Commit

Permalink
fix(android): use a crossbeam channel instead of a Mutex<VecDeque> (#761
Browse files Browse the repository at this point in the history
)
  • Loading branch information
jkelleyrtp authored Jul 15, 2023
1 parent 3b35157 commit 9a32088
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changes/android-deadlock-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

On Android, use a lockfree queue (crossbeam channel) to prevent deadlocks inside send_event.
19 changes: 11 additions & 8 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
monitor,
window::{self, Theme, WindowSizeConstraints},
};
use crossbeam_channel::{Receiver, Sender};
use ndk::{
configuration::Configuration,
event::{InputEvent, KeyAction, MotionAction},
Expand All @@ -26,7 +27,7 @@ use raw_window_handle::{
use std::{
collections::VecDeque,
convert::TryInto,
sync::{Arc, Mutex, RwLock},
sync::RwLock,
time::{Duration, Instant},
};

Expand Down Expand Up @@ -117,7 +118,8 @@ impl MenuItemAttributes {

pub struct EventLoop<T: 'static> {
window_target: event_loop::EventLoopWindowTarget<T>,
user_queue: Arc<Mutex<VecDeque<T>>>,
receiver: Receiver<T>,
sender_to_clone: Sender<T>,
first_event: Option<EventSource>,
start_cause: event::StartCause,
looper: ThreadLooper,
Expand All @@ -136,14 +138,16 @@ macro_rules! call_event_handler {

impl<T: 'static> EventLoop<T> {
pub fn new() -> Self {
let (sender, receiver) = crossbeam_channel::unbounded();
Self {
window_target: event_loop::EventLoopWindowTarget {
p: EventLoopWindowTarget {
_marker: std::marker::PhantomData,
},
_marker: std::marker::PhantomData,
},
user_queue: Default::default(),
sender_to_clone: sender,
receiver,
first_event: None,
start_cause: event::StartCause::Init,
looper: ThreadLooper::for_thread().unwrap(),
Expand Down Expand Up @@ -345,8 +349,7 @@ impl<T: 'static> EventLoop<T> {
}
}
Some(EventSource::User) => {
let mut user_queue = self.user_queue.lock().unwrap();
while let Some(event) = user_queue.pop_front() {
while let Ok(event) = self.receiver.try_recv() {
call_event_handler!(
event_handler,
self.window_target(),
Expand Down Expand Up @@ -446,20 +449,20 @@ impl<T: 'static> EventLoop<T> {

pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
queue: self.user_queue.clone(),
queue: self.sender_to_clone.clone(),
looper: ForeignLooper::for_thread().expect("called from event loop thread"),
}
}
}

pub struct EventLoopProxy<T: 'static> {
queue: Arc<Mutex<VecDeque<T>>>,
queue: Sender<T>,
looper: ForeignLooper,
}

impl<T> EventLoopProxy<T> {
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
self.queue.lock().unwrap().push_back(event);
_ = self.queue.try_send(event);
self.looper.wake();
Ok(())
}
Expand Down

0 comments on commit 9a32088

Please sign in to comment.