kms: Close drm fds via session

This commit is contained in:
Victoria Brekenfeld 2025-09-05 14:00:25 +02:00 committed by Victoria Brekenfeld
parent cad5ed8945
commit 6eb5ca1f94
2 changed files with 55 additions and 9 deletions

View file

@ -50,6 +50,7 @@ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt, fmt,
os::fd::OwnedFd,
path::Path, path::Path,
sync::{atomic::AtomicBool, mpsc::Receiver, Arc, RwLock}, sync::{atomic::AtomicBool, mpsc::Receiver, Arc, RwLock},
time::Duration, time::Duration,
@ -486,7 +487,7 @@ impl State {
.with_context(|| format!("Couldn't find drm node for {}", dev))?; .with_context(|| format!("Couldn't find drm node for {}", dev))?;
let mut outputs_removed = Vec::new(); let mut outputs_removed = Vec::new();
if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) { let device_fd = if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) {
if let Some(mut leasing_global) = device.inner.leasing_global.take() { if let Some(mut leasing_global) = device.inner.leasing_global.take() {
leasing_global.disable_global::<State>(); leasing_global.disable_global::<State>();
} }
@ -509,6 +510,10 @@ impl State {
.write() .write()
.unwrap() .unwrap()
.take_if(|node| node == &device.inner.render_node); .take_if(|node| node == &device.inner.render_node);
Some(device.drm.device().device_fd().device_fd())
} else {
None
}; };
self.common self.common
.output_configuration_state .output_configuration_state
@ -523,6 +528,19 @@ impl State {
} }
backend.refresh_used_devices()?; backend.refresh_used_devices()?;
if let Some(fd) = device_fd {
match TryInto::<OwnedFd>::try_into(fd) {
Ok(fd) => {
if let Err(err) = backend.session.close(fd) {
warn!("Failed to close drm device fd: {}", err);
}
}
Err(_) => {
warn!(?drm_node, "Unable to close drm device fd cleanly.");
}
};
}
Ok(()) Ok(())
} }

View file

@ -87,7 +87,7 @@ use smithay::{
shm::{shm_format_to_fourcc, with_buffer_contents}, shm::{shm_format_to_fourcc, with_buffer_contents},
}, },
}; };
use tracing::{error, trace, warn}; use tracing::{error, info, trace, warn};
use std::{ use std::{
borrow::{Borrow, BorrowMut}, borrow::{Borrow, BorrowMut},
@ -98,6 +98,7 @@ use std::{
mpsc::{Receiver, SyncSender}, mpsc::{Receiver, SyncSender},
Arc, RwLock, Arc, RwLock,
}, },
thread::JoinHandle,
time::Duration, time::Duration,
}; };
@ -124,6 +125,7 @@ pub struct Surface {
loop_handle: LoopHandle<'static, State>, loop_handle: LoopHandle<'static, State>,
thread_command: Sender<ThreadCommand>, thread_command: Sender<ThreadCommand>,
thread_token: RegistrationToken, thread_token: RegistrationToken,
thread: Option<JoinHandle<()>>,
dpms: bool, dpms: bool,
} }
@ -213,9 +215,11 @@ pub enum ThreadCommand {
node: DrmNode, node: DrmNode,
gbm: GbmAllocator<DrmDeviceFd>, gbm: GbmAllocator<DrmDeviceFd>,
egl: EGLContext, // TODO: Option for software rendering egl: EGLContext, // TODO: Option for software rendering
sync: SyncSender<()>,
}, },
NodeRemoved { NodeRemoved {
node: DrmNode, node: DrmNode,
sync: SyncSender<()>,
}, },
UpdateMirroring(Option<Output>), UpdateMirroring(Option<Output>),
UpdateScreenFilter(ScreenFilter), UpdateScreenFilter(ScreenFilter),
@ -262,7 +266,7 @@ impl Surface {
let active_clone = active.clone(); let active_clone = active.clone();
let output_clone = output.clone(); let output_clone = output.clone();
std::thread::Builder::new() let thread = std::thread::Builder::new()
.name(format!("surface-{}", output.name())) .name(format!("surface-{}", output.name()))
.spawn(move || { .spawn(move || {
if let Err(err) = surface_thread( if let Err(err) = surface_thread(
@ -350,6 +354,7 @@ impl Surface {
loop_handle: evlh.clone(), loop_handle: evlh.clone(),
thread_command: tx, thread_command: tx,
thread_token, thread_token,
thread: Some(thread),
dpms: true, dpms: true,
}) })
} }
@ -364,17 +369,26 @@ impl Surface {
pub fn add_node(&mut self, node: DrmNode, gbm: GbmAllocator<DrmDeviceFd>, egl: EGLContext) { pub fn add_node(&mut self, node: DrmNode, gbm: GbmAllocator<DrmDeviceFd>, egl: EGLContext) {
self.known_nodes.insert(node); self.known_nodes.insert(node);
let _ = self let (tx, rx) = std::sync::mpsc::sync_channel(1);
.thread_command let _ = self.thread_command.send(ThreadCommand::NodeAdded {
.send(ThreadCommand::NodeAdded { node, gbm, egl }); node,
gbm,
egl,
sync: tx,
});
let _ = rx.recv();
} }
pub fn remove_node(&mut self, node: DrmNode) { pub fn remove_node(&mut self, node: DrmNode) {
self.known_nodes.remove(&node); self.known_nodes.remove(&node);
self.feedback.remove(&node); self.feedback.remove(&node);
let (tx, rx) = std::sync::mpsc::sync_channel(1);
let _ = self let _ = self
.thread_command .thread_command
.send(ThreadCommand::NodeRemoved { node }); .send(ThreadCommand::NodeRemoved { node, sync: tx });
// Block so we can be sure the file descriptor is closed
// (which is relevant for the udev device_removed callback).
let _ = rx.recv();
} }
pub fn on_vblank(&self, metadata: Option<DrmEventMetadata>) { pub fn on_vblank(&self, metadata: Option<DrmEventMetadata>) {
@ -460,6 +474,11 @@ impl Drop for Surface {
fn drop(&mut self) { fn drop(&mut self) {
let _ = self.thread_command.send(ThreadCommand::End); let _ = self.thread_command.send(ThreadCommand::End);
self.loop_handle.remove(self.thread_token); self.loop_handle.remove(self.thread_token);
if let Some(thread) = self.thread.take() {
let name = thread.thread().name().unwrap().to_string();
let _ = thread.join();
info!("Thread {} terminated.", name)
}
} }
} }
@ -547,13 +566,20 @@ fn surface_thread(
Event::Msg(ThreadCommand::Resume { compositor }) => { Event::Msg(ThreadCommand::Resume { compositor }) => {
state.resume(compositor); state.resume(compositor);
} }
Event::Msg(ThreadCommand::NodeAdded { node, gbm, egl }) => { Event::Msg(ThreadCommand::NodeAdded {
node,
gbm,
egl,
sync,
}) => {
if let Err(err) = state.node_added(node, gbm, egl) { if let Err(err) = state.node_added(node, gbm, egl) {
warn!(?err, ?node, "Failed to add node to surface-thread"); warn!(?err, ?node, "Failed to add node to surface-thread");
} }
let _ = sync.send(());
} }
Event::Msg(ThreadCommand::NodeRemoved { node }) => { Event::Msg(ThreadCommand::NodeRemoved { node, sync }) => {
state.node_removed(node); state.node_removed(node);
let _ = sync.send(());
} }
Event::Msg(ThreadCommand::VBlank(metadata)) => { Event::Msg(ThreadCommand::VBlank(metadata)) => {
state.on_vblank(metadata); state.on_vblank(metadata);
@ -716,6 +742,8 @@ impl SurfaceThreadState {
fn node_removed(&mut self, node: DrmNode) { fn node_removed(&mut self, node: DrmNode) {
self.api.as_mut().remove_node(&node); self.api.as_mut().remove_node(&node);
// force enumeration
let _ = self.api.devices();
//self.software_api.as_mut().remove_node(node); //self.software_api.as_mut().remove_node(node);
} }