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"
async-broadcast = "0.3.3"
async-trait = "0.1.48"
async-lock = "2.3.0"

View File

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

View File

@ -20,13 +20,16 @@ impl Handler {
widget
.model()
.connect_items_changed(clone!(@weak widget => move |model, pos, _rm, add| {
let usbredir = usbredir.clone();
MainContext::default().spawn_local(clone!(@weak model => async move {
for pos in pos..pos + add {
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)).unwrap();
item.set_property("active", usbredir.is_device_connected(&dev).await).unwrap();
}
}
}));
}));
let usbredir = self.usbredir.clone();
widget.connect_device_state_set(move |widget, item, state| {
@ -55,7 +58,7 @@ impl Handler {
widget
.set_property("free-channels", usbredir.n_free_channels().await)
.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 {
widget.set_property("free-channels", n).unwrap();
}