qd: replace RefCell with async mutex

Avoid potential run-time borrowing errors across async points.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2021-10-12 11:38:52 +04:00
parent ab44cda4b9
commit 8c5fa2a4f9
3 changed files with 23 additions and 15 deletions

View File

@ -22,3 +22,4 @@ futures = "0.3.13"
usbredirhost = "0.0.1" usbredirhost = "0.0.1"
async-broadcast = "0.3.3" async-broadcast = "0.3.3"
async-trait = "0.1.48" async-trait = "0.1.48"
async-lock = "2.3.0"

View File

@ -1,7 +1,7 @@
use async_broadcast::{broadcast, Receiver, Sender}; use async_broadcast::{broadcast, Receiver, Sender};
use async_lock::RwLock;
use futures::Stream; use futures::Stream;
use std::{ use std::{
cell::RefCell,
collections::HashMap, collections::HashMap,
default::Default, default::Default,
io::{Read, Write}, io::{Read, Write},
@ -210,7 +210,7 @@ impl Inner {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct UsbRedir { pub struct UsbRedir {
inner: Arc<RefCell<Inner>>, inner: Arc<RwLock<Inner>>,
} }
impl UsbRedir { impl UsbRedir {
@ -218,7 +218,7 @@ impl UsbRedir {
let mut channel = broadcast(1); let mut channel = broadcast(1);
channel.0.set_overflow(true); channel.0.set_overflow(true);
Self { Self {
inner: Arc::new(RefCell::new(Inner { inner: Arc::new(RwLock::new(Inner {
chardevs, chardevs,
channel, channel,
handlers: Default::default(), handlers: Default::default(),
@ -231,7 +231,7 @@ impl UsbRedir {
device: &rusb::Device<rusb::Context>, device: &rusb::Device<rusb::Context>,
state: bool, state: bool,
) -> Result<bool> { ) -> Result<bool> {
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.write().await;
let key = Key::from_device(device); let key = Key::from_device(device);
let handled = inner.handlers.contains_key(&key); let handled = inner.handlers.contains_key(&key);
// We should do better and watch for owner properties changes, but this would require tasks // We should do better and watch for owner properties changes, but this would require tasks
@ -262,19 +262,23 @@ impl UsbRedir {
Ok(state) Ok(state)
} }
pub fn is_device_connected(&self, device: &rusb::Device<rusb::Context>) -> bool { pub async fn is_device_connected(&self, device: &rusb::Device<rusb::Context>) -> bool {
let inner = self.inner.borrow(); let inner = self.inner.read().await;
inner.handlers.contains_key(&Key::from_device(device)) inner.handlers.contains_key(&Key::from_device(device))
} }
pub async fn n_free_channels(&self) -> i32 { pub async fn n_free_channels(&self) -> i32 {
self.inner.borrow().n_available_chardev().await as _ let inner = self.inner.read().await;
inner.n_available_chardev().await as _
} }
pub fn receive_n_free_channels(&self) -> Pin<Box<dyn Stream<Item = i32>>> { pub async fn receive_n_free_channels(&self) -> Pin<Box<dyn Stream<Item = i32>>> {
let inner = self.inner.read().await;
Box::pin(NFreeChannelsStream { Box::pin(NFreeChannelsStream {
receiver: self.inner.borrow().channel.1.clone(), receiver: inner.channel.1.clone(),
}) })
} }
} }

View File

@ -20,12 +20,15 @@ impl Handler {
widget widget
.model() .model()
.connect_items_changed(clone!(@weak widget => move |model, pos, _rm, add| { .connect_items_changed(clone!(@weak widget => move |model, pos, _rm, add| {
for pos in pos..pos + add { let usbredir = usbredir.clone();
let item = model.item(pos).unwrap(); MainContext::default().spawn_local(clone!(@weak model => async move {
if let Some(dev) = item.downcast_ref::<rdw::UsbDevice>().unwrap().device() { for pos in pos..pos + add {
item.set_property("active", usbredir.is_device_connected(&dev)).unwrap(); let item = model.item(pos).unwrap();
if let Some(dev) = item.downcast_ref::<rdw::UsbDevice>().unwrap().device() {
item.set_property("active", usbredir.is_device_connected(&dev).await).unwrap();
}
} }
} }));
})); }));
let usbredir = self.usbredir.clone(); let usbredir = self.usbredir.clone();
@ -55,7 +58,7 @@ impl Handler {
widget widget
.set_property("free-channels", usbredir.n_free_channels().await) .set_property("free-channels", usbredir.n_free_channels().await)
.unwrap(); .unwrap();
let mut n = usbredir.receive_n_free_channels(); let mut n = usbredir.receive_n_free_channels().await;
while let Some(n) = n.next().await { while let Some(n) = n.next().await {
widget.set_property("free-channels", n).unwrap(); widget.set_property("free-channels", n).unwrap();
} }