Release session devices during teardown and tolerate removed panel outputs
This commit is contained in:
1 parent
90564e6564
commit
53ba599918
4 files changed
+113
-8
No files matched your search
@@ -0,0 +1,87 @@
|
||||
use smithay::{backend::session::Session, reexports::rustix::fs::OFlags, utils::DeviceFd};
|
||||
use std::{io, os::fd::OwnedFd, path::Path};
|
||||
|
||||
pub(super) struct SessionDevice<S: Session> {
|
||||
session: S,
|
||||
fd: Option<OwnedFd>,
|
||||
}
|
||||
|
||||
impl<S: Session> SessionDevice<S> {
|
||||
pub fn open(mut session: S, path: &Path) -> Result<Self, S::Error> {
|
||||
let fd = session.open(path, OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK)?;
|
||||
Ok(Self { session, fd: Some(fd) })
|
||||
}
|
||||
|
||||
pub fn device_fd(&self) -> io::Result<DeviceFd> {
|
||||
self.fd.as_ref().unwrap().try_clone().map(DeviceFd::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Session> Drop for SessionDevice<S> {
|
||||
fn drop(&mut self) {
|
||||
if let Err(error) = self.session.close(self.fd.take().unwrap()) {
|
||||
tracing::warn!(?error, "could not release DRM device through the session manager");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{cell::Cell, fs::File, os::fd::AsRawFd, rc::Rc};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct TestSession(Rc<Cell<Option<i32>>>);
|
||||
|
||||
impl Session for TestSession {
|
||||
type Error = ();
|
||||
fn open(&mut self, _: &Path, _: OFlags) -> Result<OwnedFd, ()> {
|
||||
if self.0.get().is_some() {
|
||||
return Err(());
|
||||
}
|
||||
let fd: OwnedFd = File::open("/dev/null").unwrap().into();
|
||||
self.0.set(Some(fd.as_raw_fd()));
|
||||
Ok(fd)
|
||||
}
|
||||
fn close(&mut self, fd: OwnedFd) -> Result<(), ()> {
|
||||
assert_eq!(self.0.replace(None), Some(fd.as_raw_fd()));
|
||||
Ok(())
|
||||
}
|
||||
fn change_vt(&mut self, _: i32) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
fn is_active(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn seat(&self) -> String {
|
||||
"seat0".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teardown_releases_original_session_lease_before_reopening() {
|
||||
let session = TestSession::default();
|
||||
for _ in 0..3 {
|
||||
let lease = SessionDevice::open(session.clone(), Path::new("/dev/null")).unwrap();
|
||||
let rendering = lease.device_fd().unwrap();
|
||||
assert_ne!(Some(rendering.as_raw_fd()), session.0.get());
|
||||
drop(rendering);
|
||||
assert!(session.0.get().is_some());
|
||||
drop(lease);
|
||||
assert!(session.0.get().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_renderer_initialization_releases_lease() {
|
||||
fn initialize(session: TestSession) -> Result<(), ()> {
|
||||
let lease = SessionDevice::open(session, Path::new("/dev/null"))?;
|
||||
let _rendering = lease.device_fd().unwrap();
|
||||
Err(())
|
||||
}
|
||||
let session = TestSession::default();
|
||||
assert!(initialize(session.clone()).is_err());
|
||||
assert!(session.0.get().is_none());
|
||||
assert!(SessionDevice::open(session, Path::new("/dev/null")).is_ok());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user