Files
feresaria/compositor/src/backends/direct/session_device.rs
T

88 lines
2.8 KiB
Rust

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());
}
}