Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions src/backend/kms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use std::{
collections::{HashMap, HashSet},
path::Path,
sync::{Arc, RwLock, atomic::AtomicBool},
time::Duration,
time::{Duration, Instant},
};

mod device;
Expand All @@ -65,6 +65,9 @@ pub use surface::Timings;

use super::render::{CLEAR_COLOR, CursorMode, output_elements};

const DEVICE_BUSY_TIMEOUT: Duration = Duration::from_secs(5);
const DEVICE_BUSY_RETRY_INTERVAL: Duration = Duration::from_millis(100);

#[derive(Debug)]
pub struct KmsState {
pub drm_devices: IndexMap<DrmNode, Device>,
Expand Down Expand Up @@ -140,12 +143,43 @@ pub fn init_backend(
});

// manually add already present gpus
//
// Taking a device fails with EBUSY while the compositor we replace is still shutting
// down. Coming up with no device at all is fatal, so retry for a bounded time.
let mut pending = udev_dispatcher
.as_source_ref()
.device_list()
.map(|(dev, path)| (dev, path.to_owned()))
.collect::<Vec<_>>();

let mut outputs = Vec::new();
for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
match state.device_added(dev, path, dh) {
Ok(added) => outputs.extend(added),
Err(err) => warn!("Failed to add device {}: {:?}", path.display(), err),
let deadline = Instant::now() + DEVICE_BUSY_TIMEOUT;
loop {
let mut errors = Vec::new();
pending.retain(|(dev, path)| match state.device_added(*dev, path, dh) {
Ok(added) => {
outputs.extend(added);
false
}
Err(err) => {
errors.push((path.clone(), err));
true
}
});

// never delay startup once some device came up, a secondary gpu may keep failing
if pending.is_empty() || !outputs.is_empty() || Instant::now() >= deadline {
for (path, err) in errors {
warn!("Failed to add device {}: {:?}", path.display(), err);
}
break;
}

info!(
"No drm device available yet, retrying in {:?}",
DEVICE_BUSY_RETRY_INTERVAL
);
std::thread::sleep(DEVICE_BUSY_RETRY_INTERVAL);
}

if let Err(err) = state.select_primary_gpu(dh) {
Expand Down
Loading