backend: migrate drm & udev

This commit is contained in:
Victor Berger 2018-04-18 09:38:35 +02:00
parent f9dbabce56
commit 7f6af94733
11 changed files with 270 additions and 200 deletions

View File

@ -37,8 +37,11 @@ pub(crate) struct DrmBackendInternal<A: Device + 'static> {
impl<A: Device + 'static> DrmBackend<A> { impl<A: Device + 'static> DrmBackend<A> {
pub(crate) fn new( pub(crate) fn new(
context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>, crtc: crtc::Handle, mode: Mode, context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>,
connectors: Vec<connector::Handle>, log: ::slog::Logger, crtc: crtc::Handle,
mode: Mode,
connectors: Vec<connector::Handle>,
log: ::slog::Logger,
) -> Result<Self> { ) -> Result<Self> {
// logger already initialized by the DrmDevice // logger already initialized by the DrmDevice
info!(log, "Initializing DrmBackend"); info!(log, "Initializing DrmBackend");
@ -351,7 +354,8 @@ impl<A: Device + 'static> DrmBackendInternal<A> {
} }
pub(crate) fn page_flip( pub(crate) fn page_flip(
&self, fb: Option<&framebuffer::Info> &self,
fb: Option<&framebuffer::Info>,
) -> ::std::result::Result<(), SwapBuffersError> { ) -> ::std::result::Result<(), SwapBuffersError> {
trace!(self.logger, "Queueing Page flip"); trace!(self.logger, "Queueing Page flip");
@ -421,7 +425,9 @@ impl<A: Device + 'static> GraphicsBackend for DrmBackend<A> {
} }
fn set_cursor_representation( fn set_cursor_representation(
&self, buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32) &self,
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
hotspot: (u32, u32),
) -> Result<()> { ) -> Result<()> {
let (w, h) = buffer.dimensions(); let (w, h) = buffer.dimensions();
debug!(self.backend.logger, "Importing cursor"); debug!(self.backend.logger, "Importing cursor");

View File

@ -233,8 +233,9 @@ use std::rc::{Rc, Weak};
use std::sync::{Arc, Once, ONCE_INIT}; use std::sync::{Arc, Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration; use std::time::Duration;
use wayland_server::{Display, EventLoopHandle}; use wayland_server::{Display, LoopToken};
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::commons::{downcast_impl, Implementation};
use wayland_server::sources::{FdEvent, FdInterest, Source};
mod backend; mod backend;
pub mod error; pub mod error;
@ -378,7 +379,10 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
/// Errors if initialization fails or the mode is not available on all given /// Errors if initialization fails or the mode is not available on all given
/// connectors. /// connectors.
pub fn create_backend<I>( pub fn create_backend<I>(
&mut self, crtc: crtc::Handle, mode: Mode, connectors: I &mut self,
crtc: crtc::Handle,
mode: Mode,
connectors: I,
) -> Result<DrmBackend<A>> ) -> Result<DrmBackend<A>>
where where
I: Into<Vec<connector::Handle>>, I: Into<Vec<connector::Handle>>,
@ -532,44 +536,66 @@ impl<A: ControlDevice + 'static> Drop for DrmDevice<A> {
pub trait DrmHandler<A: ControlDevice + 'static> { pub trait DrmHandler<A: ControlDevice + 'static> {
/// The `DrmBackend` of crtc has finished swapping buffers and new frame can now /// The `DrmBackend` of crtc has finished swapping buffers and new frame can now
/// (and should be immediately) be rendered. /// (and should be immediately) be rendered.
fn ready( fn ready(&mut self, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32, duration: Duration);
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32,
duration: Duration,
);
/// The `DrmDevice` has thrown an error. /// The `DrmDevice` has thrown an error.
/// ///
/// The related backends are most likely *not* usable anymore and /// The related backends are most likely *not* usable anymore and
/// the whole stack has to be recreated.. /// the whole stack has to be recreated..
fn error(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, error: DrmError); fn error(&mut self, device: &mut DrmDevice<A>, error: DrmError);
} }
/// Bind a `DrmDevice` to an `EventLoop`, /// Bind a `DrmDevice` to an `EventLoop`,
/// ///
/// This will cause it to recieve events and feed them into an `DrmHandler` /// This will cause it to recieve events and feed them into an `DrmHandler`
pub fn drm_device_bind<A, H>( pub fn drm_device_bind<A, H>(
evlh: &mut EventLoopHandle, device: DrmDevice<A>, handler: H token: &LoopToken,
) -> ::std::result::Result<FdEventSource<(DrmDevice<A>, H)>, (IoError, (DrmDevice<A>, H))> device: DrmDevice<A>,
handler: H,
) -> ::std::result::Result<(Source<FdEvent>, Rc<RefCell<DrmDevice<A>>>), (IoError, (DrmDevice<A>, H))>
where where
A: ControlDevice + 'static, A: ControlDevice + 'static,
H: DrmHandler<A> + 'static, H: DrmHandler<A> + 'static,
{ {
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
evlh.add_fd_event_source( let device = Rc::new(RefCell::new(device));
match token.add_fd_event_source(
fd, fd,
fd_event_source_implementation(),
(device, handler),
FdInterest::READ, FdInterest::READ,
) DrmFdImpl {
device: device.clone(),
handler,
},
) {
Ok(source) => Ok((source, device)),
Err((
ioerror,
DrmFdImpl {
device: device2,
handler,
},
)) => {
// make the Rc unique again
::std::mem::drop(device2);
let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!());
Err((ioerror, (device.into_inner(), handler)))
}
}
} }
fn fd_event_source_implementation<A, H>() -> FdEventSourceImpl<(DrmDevice<A>, H)> struct DrmFdImpl<A: ControlDevice + 'static, H> {
device: Rc<RefCell<DrmDevice<A>>>,
handler: H,
}
impl<A, H> Implementation<(), FdEvent> for DrmFdImpl<A, H>
where where
A: ControlDevice + 'static, A: ControlDevice + 'static,
H: DrmHandler<A> + 'static, H: DrmHandler<A> + 'static,
{ {
FdEventSourceImpl { fn receive(&mut self, event: FdEvent, (): ()) {
ready: |evlh, &mut (ref mut device, ref mut handler), _, _| { let mut device = self.device.borrow_mut();
match crtc::receive_events(device) { match event {
FdEvent::Ready { .. } => match crtc::receive_events(&mut *device) {
Ok(events) => for event in events { Ok(events) => for event in events {
if let crtc::Event::PageFlip(event) = event { if let crtc::Event::PageFlip(event) = event {
if device.active.load(Ordering::SeqCst) { if device.active.load(Ordering::SeqCst) {
@ -584,20 +610,21 @@ where
backend.unlock_buffer(); backend.unlock_buffer();
trace!(device.logger, "Handling event for backend {:?}", event.crtc); trace!(device.logger, "Handling event for backend {:?}", event.crtc);
// and then call the user to render the next frame // and then call the user to render the next frame
handler.ready(evlh, device, event.crtc, event.frame, event.duration); self.handler
.ready(&mut device, event.crtc, event.frame, event.duration);
} else { } else {
device.backends.borrow_mut().remove(&event.crtc); device.backends.borrow_mut().remove(&event.crtc);
} }
} }
} }
}, },
Err(err) => handler.error(evlh, device, err), Err(err) => self.handler.error(&mut device, err),
};
}, },
error: |evlh, &mut (ref mut device, ref mut handler), _, error| { FdEvent::Error { error, .. } => {
warn!(device.logger, "DrmDevice errored: {}", error); warn!(device.logger, "DrmDevice errored: {}", error);
handler.error(evlh, device, error.into()); self.handler.error(&mut device, error.into());
}, }
}
} }
} }
@ -629,7 +656,7 @@ impl<A: ControlDevice + 'static> AsSessionObserver<DrmDeviceObserver<A>> for Drm
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> { impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
fn pause(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) { fn pause(&mut self, devnum: Option<(u32, u32)>) {
if let Some((major, minor)) = devnum { if let Some((major, minor)) = devnum {
if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) { if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) {
return; return;
@ -665,7 +692,7 @@ impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
} }
} }
fn activate(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) { fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
if let Some((major, minor, fd)) = devnum { if let Some((major, minor, fd)) = devnum {
if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) { if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) {
return; return;

View File

@ -50,7 +50,10 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> DerefMut for EGLContext<B,
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> { impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
/// Create a new `EGLContext` from a given `NativeDisplay` /// Create a new `EGLContext` from a given `NativeDisplay`
pub fn new<L>( pub fn new<L>(
native: N, attributes: GlAttributes, reqs: PixelFormatRequirements, logger: L native: N,
attributes: GlAttributes,
reqs: PixelFormatRequirements,
logger: L,
) -> Result<EGLContext<B, N>> ) -> Result<EGLContext<B, N>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
@ -82,7 +85,9 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
} }
unsafe fn new_internal( unsafe fn new_internal(
ptr: ffi::NativeDisplayType, mut attributes: GlAttributes, reqs: PixelFormatRequirements, ptr: ffi::NativeDisplayType,
mut attributes: GlAttributes,
reqs: PixelFormatRequirements,
log: ::slog::Logger, log: ::slog::Logger,
) -> Result< ) -> Result<
( (

View File

@ -42,7 +42,8 @@ pub mod egl {
#[allow(non_snake_case, unused_variables, dead_code)] #[allow(non_snake_case, unused_variables, dead_code)]
#[inline] #[inline]
pub unsafe fn BindWaylandDisplayWL( pub unsafe fn BindWaylandDisplayWL(
dpy: types::EGLDisplay, display: *mut __gl_imports::raw::c_void dpy: types::EGLDisplay,
display: *mut __gl_imports::raw::c_void,
) -> types::EGLBoolean { ) -> types::EGLBoolean {
__gl_imports::mem::transmute::< __gl_imports::mem::transmute::<
_, _,
@ -53,7 +54,8 @@ pub mod egl {
#[allow(non_snake_case, unused_variables, dead_code)] #[allow(non_snake_case, unused_variables, dead_code)]
#[inline] #[inline]
pub unsafe fn UnbindWaylandDisplayWL( pub unsafe fn UnbindWaylandDisplayWL(
dpy: types::EGLDisplay, display: *mut __gl_imports::raw::c_void dpy: types::EGLDisplay,
display: *mut __gl_imports::raw::c_void,
) -> types::EGLBoolean { ) -> types::EGLBoolean {
__gl_imports::mem::transmute::< __gl_imports::mem::transmute::<
_, _,
@ -64,7 +66,9 @@ pub mod egl {
#[allow(non_snake_case, unused_variables, dead_code)] #[allow(non_snake_case, unused_variables, dead_code)]
#[inline] #[inline]
pub unsafe fn QueryWaylandBufferWL( pub unsafe fn QueryWaylandBufferWL(
dpy: types::EGLDisplay, buffer: *mut __gl_imports::raw::c_void, attribute: types::EGLint, dpy: types::EGLDisplay,
buffer: *mut __gl_imports::raw::c_void,
attribute: types::EGLint,
value: *mut types::EGLint, value: *mut types::EGLint,
) -> types::EGLBoolean { ) -> types::EGLBoolean {
__gl_imports::mem::transmute::< __gl_imports::mem::transmute::<

View File

@ -31,7 +31,9 @@ pub trait Backend {
/// The returned `EGLDisplay` needs to be a valid ptr for egl, /// The returned `EGLDisplay` needs to be a valid ptr for egl,
/// but there is no way to test that. /// but there is no way to test that.
unsafe fn get_display<F: Fn(&str) -> bool>( unsafe fn get_display<F: Fn(&str) -> bool>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay; ) -> ffi::egl::types::EGLDisplay;
} }
@ -43,7 +45,9 @@ impl Backend for Wayland {
type Surface = wegl::WlEglSurface; type Surface = wegl::WlEglSurface;
unsafe fn get_display<F>( unsafe fn get_display<F>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay ) -> ffi::egl::types::EGLDisplay
where where
F: Fn(&str) -> bool, F: Fn(&str) -> bool,
@ -87,7 +91,9 @@ impl Backend for X11 {
type Surface = XlibWindow; type Surface = XlibWindow;
unsafe fn get_display<F>( unsafe fn get_display<F>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay ) -> ffi::egl::types::EGLDisplay
where where
F: Fn(&str) -> bool, F: Fn(&str) -> bool,
@ -114,7 +120,9 @@ impl<T: 'static> Backend for Gbm<T> {
type Surface = GbmSurface<T>; type Surface = GbmSurface<T>;
unsafe fn get_display<F>( unsafe fn get_display<F>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay ) -> ffi::egl::types::EGLDisplay
where where
F: Fn(&str) -> bool, F: Fn(&str) -> bool,

View File

@ -30,7 +30,8 @@ impl<N: native::NativeSurface> DerefMut for EGLSurface<N> {
impl<N: native::NativeSurface> EGLSurface<N> { impl<N: native::NativeSurface> EGLSurface<N> {
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>( pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
context: &EGLContext<B, D>, native: N context: &EGLContext<B, D>,
native: N,
) -> Result<EGLSurface<N>> { ) -> Result<EGLSurface<N>> {
let surface = unsafe { let surface = unsafe {
ffi::egl::CreateWindowSurface( ffi::egl::CreateWindowSurface(

View File

@ -192,7 +192,9 @@ impl EGLImages {
/// ///
/// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur. /// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur.
pub unsafe fn bind_to_texture( pub unsafe fn bind_to_texture(
&self, plane: usize, tex_id: c_uint &self,
plane: usize,
tex_id: c_uint,
) -> ::std::result::Result<(), TextureCreationError> { ) -> ::std::result::Result<(), TextureCreationError> {
if self.display.upgrade().is_some() { if self.display.upgrade().is_some() {
let mut old_tex_id: i32 = 0; let mut old_tex_id: i32 = 0;
@ -255,7 +257,8 @@ pub struct EGLDisplay(Weak<ffi::egl::types::EGLDisplay>, *mut wl_display);
impl EGLDisplay { impl EGLDisplay {
fn new<B: native::Backend, N: native::NativeDisplay<B>>( fn new<B: native::Backend, N: native::NativeDisplay<B>>(
context: &EGLContext<B, N>, display: *mut wl_display context: &EGLContext<B, N>,
display: *mut wl_display,
) -> EGLDisplay { ) -> EGLDisplay {
EGLDisplay(Rc::downgrade(&context.display), display) EGLDisplay(Rc::downgrade(&context.display), display)
} }
@ -266,7 +269,8 @@ impl EGLDisplay {
/// a `BufferAccessError::NotManaged(WlBuffer)` is returned with the original buffer /// a `BufferAccessError::NotManaged(WlBuffer)` is returned with the original buffer
/// to render it another way. /// to render it another way.
pub fn egl_buffer_contents( pub fn egl_buffer_contents(
&self, buffer: Resource<WlBuffer> &self,
buffer: Resource<WlBuffer>,
) -> ::std::result::Result<EGLImages, BufferAccessError> { ) -> ::std::result::Result<EGLImages, BufferAccessError> {
if let Some(display) = self.0.upgrade() { if let Some(display) = self.0.upgrade() {
let mut format: i32 = 0; let mut format: i32 = 0;

View File

@ -30,7 +30,9 @@ pub trait GraphicsBackend {
/// from raw image buffers over a fixed list of possible cursor types to simply the /// from raw image buffers over a fixed list of possible cursor types to simply the
/// void type () to represent no possible customization of the cursor itself. /// void type () to represent no possible customization of the cursor itself.
fn set_cursor_representation( fn set_cursor_representation(
&self, cursor: &Self::CursorFormat, hotspot: (u32, u32) &self,
cursor: &Self::CursorFormat,
hotspot: (u32, u32),
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
} }

View File

@ -19,11 +19,11 @@ pub mod graphics;
//#[cfg(feature = "backend_winit")] //#[cfg(feature = "backend_winit")]
//pub mod winit; //pub mod winit;
//#[cfg(feature = "backend_drm")] #[cfg(feature = "backend_drm")]
//pub mod drm; pub mod drm;
//#[cfg(feature = "backend_libinput")] //#[cfg(feature = "backend_libinput")]
//pub mod libinput; //pub mod libinput;
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
pub mod session; pub mod session;
//#[cfg(feature = "backend_udev")] #[cfg(feature = "backend_udev")]
//pub mod udev; pub mod udev;

View File

@ -451,11 +451,7 @@ pub fn logind_session_bind(
let mut interest = FdInterest::empty(); let mut interest = FdInterest::empty();
interest.set(FdInterest::READ, watch.readable()); interest.set(FdInterest::READ, watch.readable());
interest.set(FdInterest::WRITE, watch.writable()); interest.set(FdInterest::WRITE, watch.writable());
token.add_fd_event_source( token.add_fd_event_source(watch.fd(), interest, notifier.clone())
watch.fd(),
interest,
notifier.clone(),
)
}) })
.collect::<::std::result::Result<Vec<Source<FdEvent>>, (IoError, _)>>() .collect::<::std::result::Result<Vec<Source<FdEvent>>, (IoError, _)>>()
.map_err(|(err, _)| { .map_err(|(err, _)| {

View File

@ -24,8 +24,9 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult}; use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult};
use wayland_server::EventLoopHandle; use wayland_server::LoopToken;
use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::commons::Implementation;
use wayland_server::sources::{FdEvent, FdInterest, Source};
/// Udev's `DrmDevice` type based on the underlying session /// Udev's `DrmDevice` type based on the underlying session
pub struct SessionFdDrmDevice(RawFd); pub struct SessionFdDrmDevice(RawFd);
@ -48,11 +49,13 @@ pub struct UdevBackend<
S: Session + 'static, S: Session + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
> { > {
devices: Rc<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>, _handler: ::std::marker::PhantomData<H>,
devices: Rc<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
monitor: MonitorSocket, monitor: MonitorSocket,
session: S, session: S,
handler: T, handler: T,
logger: ::slog::Logger, logger: ::slog::Logger,
token: LoopToken,
} }
impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevHandler<H> + 'static> impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevHandler<H> + 'static>
@ -67,7 +70,11 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
/// `handler` - User-provided handler to respond to any detected changes /// `handler` - User-provided handler to respond to any detected changes
/// `logger` - slog Logger to be used by the backend and its `DrmDevices`. /// `logger` - slog Logger to be used by the backend and its `DrmDevices`.
pub fn new<'a, L>( pub fn new<'a, L>(
mut evlh: &mut EventLoopHandle, context: &Context, mut session: S, mut handler: T, logger: L token: LoopToken,
context: &Context,
mut session: S,
mut handler: T,
logger: L,
) -> Result<UdevBackend<H, S, T>> ) -> Result<UdevBackend<H, S, T>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
@ -81,7 +88,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
.flat_map(|path| { .flat_map(|path| {
match DrmDevice::new( match DrmDevice::new(
{ {
match session.open(&path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) { match session.open(&path, fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC | fcntl::OFlag::O_NOCTTY | fcntl::OFlag::O_NONBLOCK) {
Ok(fd) => SessionFdDrmDevice(fd), Ok(fd) => SessionFdDrmDevice(fd),
Err(err) => { Err(err) => {
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err); warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
@ -94,13 +101,13 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
Ok(mut device) => { Ok(mut device) => {
let devnum = device.device_id(); let devnum = device.device_id();
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
match handler.device_added(evlh, &mut device) { match handler.device_added(&mut device) {
Some(drm_handler) => { Some(drm_handler) => {
match drm_device_bind(&mut evlh, device, drm_handler) { match drm_device_bind(&token, device, drm_handler) {
Ok(event_source) => Some((devnum, event_source)), Ok((event_source, device)) => Some((devnum, (event_source, device))),
Err((err, (mut device, _))) => { Err((err, (mut device, _))) => {
warn!(logger, "Failed to bind device. Error: {:?}.", err); warn!(logger, "Failed to bind device. Error: {:?}.", err);
handler.device_removed(evlh, &mut device); handler.device_removed(&mut device);
drop(device); drop(device);
if let Err(err) = session.close(fd) { if let Err(err) = session.close(fd) {
warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err); warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
@ -124,7 +131,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
} }
} }
}) })
.collect::<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>(); .collect::<HashMap<dev_t, _>>();
let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?; let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?;
builder builder
@ -135,20 +142,25 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
.chain_err(|| ErrorKind::FailedToInitMonitor)?; .chain_err(|| ErrorKind::FailedToInitMonitor)?;
Ok(UdevBackend { Ok(UdevBackend {
_handler: ::std::marker::PhantomData,
devices: Rc::new(RefCell::new(devices)), devices: Rc::new(RefCell::new(devices)),
monitor, monitor,
session, session,
handler, handler,
logger, logger,
token,
}) })
} }
/// Closes the udev backend and frees all remaining open devices. /// Closes the udev backend and frees all remaining open devices.
pub fn close(&mut self, evlh: &mut EventLoopHandle) { pub fn close(&mut self) {
let mut devices = self.devices.borrow_mut(); let mut devices = self.devices.borrow_mut();
for (_, event_source) in devices.drain() { for (_, (event_source, device)) in devices.drain() {
let (mut device, _) = event_source.remove(); event_source.remove();
self.handler.device_removed(evlh, &mut device); let mut device = Rc::try_unwrap(device)
.unwrap_or_else(|_| unreachable!())
.into_inner();
self.handler.device_removed(&mut device);
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
drop(device); drop(device);
if let Err(err) = self.session.close(fd) { if let Err(err) = self.session.close(fd) {
@ -163,8 +175,8 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
} }
/// `SessionObserver` linked to the `UdevBackend` it was created from. /// `SessionObserver` linked to the `UdevBackend` it was created from.
pub struct UdevBackendObserver<H: DrmHandler<SessionFdDrmDevice> + 'static> { pub struct UdevBackendObserver {
devices: Weak<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>, devices: Weak<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
@ -172,9 +184,9 @@ impl<
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
S: Session + 'static, S: Session + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
> AsSessionObserver<UdevBackendObserver<H>> for UdevBackend<H, S, T> > AsSessionObserver<UdevBackendObserver> for UdevBackend<H, S, T>
{ {
fn observer(&mut self) -> UdevBackendObserver<H> { fn observer(&mut self) -> UdevBackendObserver {
UdevBackendObserver { UdevBackendObserver {
devices: Rc::downgrade(&self.devices), devices: Rc::downgrade(&self.devices),
logger: self.logger.clone(), logger: self.logger.clone(),
@ -182,25 +194,21 @@ impl<
} }
} }
impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBackendObserver<H> { impl SessionObserver for UdevBackendObserver {
fn pause<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) { fn pause<'a>(&mut self, devnum: Option<(u32, u32)>) {
if let Some(devices) = self.devices.upgrade() { if let Some(devices) = self.devices.upgrade() {
for fd_event_source in devices.borrow_mut().values_mut() { for &mut (_, ref device) in devices.borrow_mut().values_mut() {
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
info!(self.logger, "changed successful"); info!(self.logger, "changed successful");
device.observer().pause(evlh, devnum); device.borrow_mut().observer().pause(devnum);
})
} }
} }
} }
fn activate<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) { fn activate<'a>(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
if let Some(devices) = self.devices.upgrade() { if let Some(devices) = self.devices.upgrade() {
for fd_event_source in devices.borrow_mut().values_mut() { for &mut (_, ref device) in devices.borrow_mut().values_mut() {
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
info!(self.logger, "changed successful"); info!(self.logger, "changed successful");
device.observer().activate(evlh, devnum); device.borrow_mut().observer().activate(devnum);
})
} }
} }
} }
@ -210,41 +218,44 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBacken
/// ///
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`. /// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
/// No runtime functionality can be provided without using this function. /// No runtime functionality can be provided without using this function.
pub fn udev_backend_bind<S, H, T>( pub fn udev_backend_bind<H, S, T>(
evlh: &mut EventLoopHandle, udev: UdevBackend<H, S, T> token: &LoopToken,
) -> ::std::result::Result<FdEventSource<UdevBackend<H, S, T>>, (IoError, UdevBackend<H, S, T>)> udev: UdevBackend<H, S, T>,
) -> ::std::result::Result<Source<FdEvent>, (IoError, UdevBackend<H, S, T>)>
where where
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
S: Session + 'static, S: Session + 'static,
{ {
let fd = udev.monitor.as_raw_fd(); let fd = udev.monitor.as_raw_fd();
evlh.add_fd_event_source(fd, fd_event_source_implementation(), udev, FdInterest::READ) token.add_fd_event_source(fd, FdInterest::READ, udev)
} }
fn fd_event_source_implementation<S, H, T>() -> FdEventSourceImpl<UdevBackend<H, S, T>> impl<H, S, T> Implementation<(), FdEvent> for UdevBackend<H, S, T>
where where
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
S: Session + 'static, S: Session + 'static,
{ {
FdEventSourceImpl { fn receive(&mut self, event: FdEvent, (): ()) {
ready: |mut evlh, udev, _, _| { match event {
let events = udev.monitor.clone().collect::<Vec<Event>>(); FdEvent::Ready { .. } => {
let events = self.monitor.clone().collect::<Vec<Event>>();
for event in events { for event in events {
match event.event_type() { match event.event_type() {
// New device // New device
EventType::Add => { EventType::Add => {
info!(udev.logger, "Device Added"); info!(self.logger, "Device Added");
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) { if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
let mut device = { let mut device = {
match DrmDevice::new( match DrmDevice::new(
{ {
let logger = udev.logger.clone(); let logger = self.logger.clone();
match udev.session.open( match self.session.open(
path, path,
fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC
| fcntl::O_NONBLOCK, | fcntl::OFlag::O_NOCTTY
| fcntl::OFlag::O_NONBLOCK,
) { ) {
Ok(fd) => SessionFdDrmDevice(fd), Ok(fd) => SessionFdDrmDevice(fd),
Err(err) => { Err(err) => {
@ -258,12 +269,12 @@ where
} }
} }
}, },
udev.logger.clone(), self.logger.clone(),
) { ) {
Ok(dev) => dev, Ok(dev) => dev,
Err(err) => { Err(err) => {
warn!( warn!(
udev.logger, self.logger,
"Failed to initialize device {:?}. Error: {}. Skipping", "Failed to initialize device {:?}. Error: {}. Skipping",
path, path,
err err
@ -273,29 +284,34 @@ where
} }
}; };
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
match udev.handler.device_added(evlh, &mut device) { match self.handler.device_added(&mut device) {
Some(drm_handler) => match drm_device_bind(&mut evlh, device, drm_handler) { Some(drm_handler) => {
match drm_device_bind(&self.token, device, drm_handler) {
Ok(fd_event_source) => { Ok(fd_event_source) => {
udev.devices.borrow_mut().insert(devnum, fd_event_source); self.devices.borrow_mut().insert(devnum, fd_event_source);
} }
Err((err, (mut device, _))) => { Err((err, (mut device, _))) => {
warn!(udev.logger, "Failed to bind device. Error: {:?}.", err);
udev.handler.device_removed(evlh, &mut device);
drop(device);
if let Err(err) = udev.session.close(fd) {
warn!( warn!(
udev.logger, self.logger,
"Failed to bind device. Error: {:?}.", err
);
self.handler.device_removed(&mut device);
drop(device);
if let Err(err) = self.session.close(fd) {
warn!(
self.logger,
"Failed to close dropped device. Error: {:?}. Ignoring", err "Failed to close dropped device. Error: {:?}. Ignoring", err
); );
}; };
} }
}, }
}
None => { None => {
udev.handler.device_removed(evlh, &mut device); self.handler.device_removed(&mut device);
drop(device); drop(device);
if let Err(err) = udev.session.close(fd) { if let Err(err) = self.session.close(fd) {
warn!( warn!(
udev.logger, self.logger,
"Failed to close unused device. Error: {:?}", err "Failed to close unused device. Error: {:?}", err
); );
} }
@ -305,16 +321,21 @@ where
} }
// Device removed // Device removed
EventType::Remove => { EventType::Remove => {
info!(udev.logger, "Device Remove"); info!(self.logger, "Device Remove");
if let Some(devnum) = event.devnum() { if let Some(devnum) = event.devnum() {
if let Some(fd_event_source) = udev.devices.borrow_mut().remove(&devnum) { if let Some((fd_event_source, device)) =
let (mut device, _) = fd_event_source.remove(); self.devices.borrow_mut().remove(&devnum)
udev.handler.device_removed(evlh, &mut device); {
fd_event_source.remove();
let mut device = Rc::try_unwrap(device)
.unwrap_or_else(|_| unreachable!())
.into_inner();
self.handler.device_removed(&mut device);
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
drop(device); drop(device);
if let Err(err) = udev.session.close(fd) { if let Err(err) = self.session.close(fd) {
warn!( warn!(
udev.logger, self.logger,
"Failed to close device {:?}. Error: {:?}. Ignoring", "Failed to close device {:?}. Error: {:?}. Ignoring",
event.sysname(), event.sysname(),
err err
@ -325,28 +346,26 @@ where
} }
// New connector // New connector
EventType::Change => { EventType::Change => {
info!(udev.logger, "Device Changed"); info!(self.logger, "Device Changed");
if let Some(devnum) = event.devnum() { if let Some(devnum) = event.devnum() {
info!(udev.logger, "Devnum: {:b}", devnum); info!(self.logger, "Devnum: {:b}", devnum);
if let Some(fd_event_source) = udev.devices.borrow_mut().get_mut(&devnum) { if let Some(&(_, ref device)) = self.devices.borrow_mut().get(&devnum) {
let handler = &mut udev.handler; let handler = &mut self.handler;
let logger = &udev.logger; let logger = &self.logger;
fd_event_source.with_idata(evlh, move |&mut (ref mut device, _), evlh| { handler.device_changed(&mut device.borrow_mut());
info!(logger, "changed successful");
handler.device_changed(evlh, device);
})
} else { } else {
info!(udev.logger, "changed, but device not tracked by backend"); info!(self.logger, "changed, but device not tracked by backend");
}; };
} else { } else {
info!(udev.logger, "changed, but no devnum"); info!(self.logger, "changed, but no devnum");
} }
} }
_ => {} _ => {}
} }
} }
}, }
error: |evlh, udev, _, err| udev.handler.error(evlh, err), FdEvent::Error { error, .. } => self.handler.error(error),
}
} }
} }
@ -358,9 +377,7 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_added( fn device_added(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>) -> Option<H>;
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
) -> Option<H>;
/// Called when an open device is changed. /// Called when an open device is changed.
/// ///
/// This usually indicates that some connectors did become available or were unplugged. The handler /// This usually indicates that some connectors did become available or were unplugged. The handler
@ -368,7 +385,7 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_changed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>); fn device_changed(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>);
/// Called when a device was removed. /// Called when a device was removed.
/// ///
/// The device will not accept any operations anymore and its file descriptor will be closed once /// The device will not accept any operations anymore and its file descriptor will be closed once
@ -376,12 +393,12 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_removed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>); fn device_removed(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>);
/// Called when the udev context has encountered and error. /// Called when the udev context has encountered and error.
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError); fn error(&mut self, error: IoError);
} }
/// Returns the path of the primary gpu device if any /// Returns the path of the primary gpu device if any