fix(bluetooth): cpu usage
This commit is contained in:
parent
9eb4053d31
commit
b6bb982f2d
2 changed files with 58 additions and 13 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::bluetooth::{BluerDeviceStatus, BluerRequest, BluerState, DeviceProperty};
|
use crate::bluetooth::{set_tick, BluerDeviceStatus, BluerRequest, BluerState, DeviceProperty};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app,
|
app,
|
||||||
applet::token::subscription::{activation_token_subscription, TokenRequest, TokenUpdate},
|
applet::token::subscription::{activation_token_subscription, TokenRequest, TokenUpdate},
|
||||||
|
|
@ -24,6 +24,7 @@ use cosmic::{
|
||||||
Element, Task,
|
Element, Task,
|
||||||
};
|
};
|
||||||
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
||||||
|
use futures::FutureExt;
|
||||||
use std::{collections::HashMap, time::Duration};
|
use std::{collections::HashMap, time::Duration};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
|
@ -112,7 +113,13 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
match message {
|
match message {
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
return destroy_popup(p);
|
return Task::batch(vec![
|
||||||
|
destroy_popup(p),
|
||||||
|
cosmic::task::future(
|
||||||
|
set_tick(Duration::from_secs(10))
|
||||||
|
.map(|_| cosmic::Action::App(Message::Ignore)),
|
||||||
|
),
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
// TODO request update of state maybe
|
// TODO request update of state maybe
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
|
|
@ -138,6 +145,8 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
|_| cosmic::action::app(Message::Ignore),
|
|_| cosmic::action::app(Message::Ignore),
|
||||||
),
|
),
|
||||||
get_popup(popup_settings),
|
get_popup(popup_settings),
|
||||||
|
cosmic::task::future(set_tick(Duration::from_secs(3)))
|
||||||
|
.map(|_: ()| cosmic::Action::App(Message::Ignore)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,6 +295,9 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
if Some(id) == self.popup {
|
if Some(id) == self.popup {
|
||||||
self.popup = None;
|
self.popup = None;
|
||||||
}
|
}
|
||||||
|
return cosmic::task::future(
|
||||||
|
set_tick(Duration::from_secs(10)).map(|_| cosmic::Action::App(Message::Ignore)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Message::OpenSettings => {
|
Message::OpenSettings => {
|
||||||
let exec = "cosmic-settings bluetooth".to_string();
|
let exec = "cosmic-settings bluetooth".to_string();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Debug, hash::Hash, mem, sync::Arc, time::Duration};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::Debug,
|
||||||
|
hash::Hash,
|
||||||
|
mem,
|
||||||
|
sync::{Arc, LazyLock},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
pub use bluer::DeviceProperty;
|
pub use bluer::DeviceProperty;
|
||||||
use bluer::{
|
use bluer::{
|
||||||
|
|
@ -24,11 +31,26 @@ use tokio::{
|
||||||
spawn,
|
spawn,
|
||||||
sync::{
|
sync::{
|
||||||
mpsc::{channel, Receiver, Sender},
|
mpsc::{channel, Receiver, Sender},
|
||||||
Mutex,
|
Mutex, RwLock,
|
||||||
},
|
},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static TICK: LazyLock<RwLock<Duration>> = LazyLock::new(|| RwLock::new(Duration::from_secs(10)));
|
||||||
|
|
||||||
|
pub async fn set_tick(duration: Duration) {
|
||||||
|
let mut guard = TICK.write().await;
|
||||||
|
*guard = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn tick(interval: &mut tokio::time::Interval) {
|
||||||
|
let guard = TICK.read().await;
|
||||||
|
if *guard != interval.period() {
|
||||||
|
*interval = tokio::time::interval(*guard);
|
||||||
|
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||||
|
}
|
||||||
|
interval.tick().await;
|
||||||
|
}
|
||||||
// Copied from https://github.com/bluez/bluez/blob/39467578207889fd015775cbe81a3db9dd26abea/src/dbus-common.c#L53
|
// Copied from https://github.com/bluez/bluez/blob/39467578207889fd015775cbe81a3db9dd26abea/src/dbus-common.c#L53
|
||||||
#[inline]
|
#[inline]
|
||||||
fn device_type_to_icon(device_type: &str) -> &'static str {
|
fn device_type_to_icon(device_type: &str) -> &'static str {
|
||||||
|
|
@ -68,8 +90,10 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
}
|
}
|
||||||
|
|
||||||
retry_count = retry_count.saturating_add(1);
|
retry_count = retry_count.saturating_add(1);
|
||||||
_ = tokio::time::sleep(Duration::from_millis(2_u64.saturating_pow(retry_count)))
|
_ = tokio::time::sleep(Duration::from_millis(
|
||||||
.await;
|
2_u64.saturating_pow(retry_count).max(68719476734),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = bluer_state(&session_state.adapter).await;
|
let state = bluer_state(&session_state.adapter).await;
|
||||||
|
|
@ -116,8 +140,8 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
_ = output.send(message).await;
|
_ = output.send(message).await;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
||||||
|
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||||
loop {
|
loop {
|
||||||
let Some(mut session_rx) = session_state.rx.take() else {
|
let Some(mut session_rx) = session_state.rx.take() else {
|
||||||
break;
|
break;
|
||||||
|
|
@ -126,8 +150,13 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
if let Some(event) = session_rx.recv().await {
|
if let Some(event) = session_rx.recv().await {
|
||||||
event_handler(event).await;
|
event_handler(event).await;
|
||||||
// Consume any additional available events.
|
// Consume any additional available events.
|
||||||
|
let mut count = 0;
|
||||||
while let Some(event) = session_rx.try_recv().ok() {
|
while let Some(event) = session_rx.try_recv().ok() {
|
||||||
event_handler(event).await;
|
event_handler(event).await;
|
||||||
|
count += 1;
|
||||||
|
if count == 100 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
@ -531,10 +560,11 @@ impl BluerSessionState {
|
||||||
let wake_up_discover_tx = self.wake_up_discover_tx.clone();
|
let wake_up_discover_tx = self.wake_up_discover_tx.clone();
|
||||||
let _handle: JoinHandle<anyhow::Result<()>> = spawn(async move {
|
let _handle: JoinHandle<anyhow::Result<()>> = spawn(async move {
|
||||||
let mut status = adapter_clone.is_powered().await.unwrap_or_default();
|
let mut status = adapter_clone.is_powered().await.unwrap_or_default();
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(3));
|
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
||||||
|
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||||
let mut devices = Vec::new();
|
let mut devices = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
interval.tick().await;
|
tick(&mut interval).await;
|
||||||
let new_status = adapter_clone.is_powered().await.unwrap_or_default();
|
let new_status = adapter_clone.is_powered().await.unwrap_or_default();
|
||||||
devices = build_device_list(devices, &adapter_clone).await;
|
devices = build_device_list(devices, &adapter_clone).await;
|
||||||
if new_status != status {
|
if new_status != status {
|
||||||
|
|
@ -569,19 +599,23 @@ impl BluerSessionState {
|
||||||
let _monitor_devices: tokio::task::JoinHandle<Result<(), anyhow::Error>> =
|
let _monitor_devices: tokio::task::JoinHandle<Result<(), anyhow::Error>> =
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
let mut devices: Vec<BluerDevice> = Vec::new();
|
let mut devices: Vec<BluerDevice> = Vec::new();
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
||||||
|
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
let wakeup_fut = wake_up.recv();
|
let wakeup_fut = wake_up.recv();
|
||||||
|
|
||||||
// Listens for process changes and builds edvice lists.
|
// Listens for process changes and builds edvice lists.
|
||||||
let listener_fut = async {
|
let listener_fut = async {
|
||||||
let mut new_devices = Vec::new();
|
let mut new_devices = Vec::new();
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
||||||
|
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||||
let mut change_stream =
|
let mut change_stream =
|
||||||
match adapter_clone.discover_devices_with_changes().await {
|
match adapter_clone.discover_devices_with_changes().await {
|
||||||
Ok(stream) => stream,
|
Ok(stream) => stream,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
interval.tick().await;
|
tick(&mut interval).await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -768,7 +802,6 @@ async fn bluer_state(adapter: &Adapter) -> BluerState {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
async fn build_device_list(mut devices: Vec<BluerDevice>, adapter: &Adapter) -> Vec<BluerDevice> {
|
async fn build_device_list(mut devices: Vec<BluerDevice>, adapter: &Adapter) -> Vec<BluerDevice> {
|
||||||
let addrs = adapter.device_addresses().await.unwrap_or_default();
|
let addrs = adapter.device_addresses().await.unwrap_or_default();
|
||||||
|
|
||||||
devices.clear();
|
devices.clear();
|
||||||
if addrs.len() > devices.capacity() {
|
if addrs.len() > devices.capacity() {
|
||||||
devices.reserve(addrs.len() - devices.capacity());
|
devices.reserve(addrs.len() - devices.capacity());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue