drm: Fix drop order

This commit is contained in:
Victor Brekenfeld 2018-11-28 09:09:34 +01:00
parent 2c73651327
commit f2466c5c50
7 changed files with 95 additions and 70 deletions

View File

@ -10,7 +10,7 @@ repository = "https://github.com/Smithay/smithay"
members = [ "anvil" ]
[dependencies]
wayland-server = "0.21.4"
wayland-server = "0.21.6"
wayland-sys = "0.21.3"
wayland-commons = "0.21.1"
nix = "0.11"

View File

@ -385,15 +385,19 @@ impl<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data>
fn device_removed(&mut self, device: dev_t) {
// drop the backends on this side
if let Some((id, evt_source, _)) = self.backends.remove(&device) {
if let Some((id, evt_source, renderers)) = self.backends.remove(&device) {
// drop surfaces
renderers.borrow_mut().clear();
debug!(self.logger, "Surfaces dropped");
// don't use hardware acceleration anymore, if this was the primary gpu
let source = evt_source.clone_inner();
let evented = source.borrow();
if (*evented).0.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu {
let device = Rc::try_unwrap(evt_source.remove().unwrap()).map_err(|_| "This should not happend").unwrap().into_inner().0;
if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu {
*self.active_egl_context.borrow_mut() = None;
}
self.notifier.unregister(id);
debug!(self.logger, "Dropping device");
}
}
}

View File

@ -25,6 +25,7 @@ pub struct EglDevice<
B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B> + 'static,
> where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
dev: Rc<EGLContext<B, D>>,
@ -34,6 +35,7 @@ pub struct EglDevice<
impl<B: Backend<Surface = <D as Device>::Surface> + 'static, D: Device + NativeDisplay<B> + 'static> AsRawFd
for EglDevice<B, D>
where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
fn as_raw_fd(&self) -> RawFd {
@ -44,6 +46,7 @@ where
impl<B: Backend<Surface = <D as Device>::Surface> + 'static, D: Device + NativeDisplay<B> + 'static>
EglDevice<B, D>
where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
/// Create a new `EglGbmDrmDevice` from an open drm node
@ -93,6 +96,7 @@ struct InternalDeviceHandler<
B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B> + 'static,
> where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
handler: Box<DeviceHandler<Device = EglDevice<B, D>> + 'static>,
@ -177,9 +181,21 @@ where
impl<B: Backend<Surface = <D as Device>::Surface> + 'static, D: Device + NativeDisplay<B> + 'static>
EGLGraphicsBackend for EglDevice<B, D>
where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
fn bind_wl_display(&self, display: &Display) -> EGLResult<EGLDisplay> {
self.dev.bind_wl_display(display)
}
}
impl<B: Backend<Surface = <D as Device>::Surface> + 'static, D: Device + NativeDisplay<B> + 'static>
Drop for EglDevice<B, D>
where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
fn drop(&mut self) {
self.clear_handler();
}
}

View File

@ -1,4 +1,5 @@
use std::os::unix::io::RawFd;
use drm::control::{crtc, connector, Mode};
use super::EglDevice;
use backend::drm::Device;
@ -16,6 +17,7 @@ impl<
D: Device + NativeDisplay<B> + AsSessionObserver<S> + 'static,
> AsSessionObserver<EglDeviceObserver<S>> for EglDevice<B, D>
where
<D as NativeDisplay<B>>::Arguments: From<(crtc::Handle, Mode, Vec<connector::Handle>)>,
<D as Device>::Surface: NativeSurface,
{
fn observer(&mut self) -> EglDeviceObserver<S> {

View File

@ -192,3 +192,9 @@ impl<D: RawDevice + ControlDevice + 'static> AsRawFd for GbmDevice<D> {
self.dev.borrow().as_raw_fd()
}
}
impl<D: RawDevice + ControlDevice + 'static> Drop for GbmDevice<D> {
fn drop(&mut self) {
self.clear_handler();
}
}

View File

@ -26,22 +26,51 @@ pub mod session;
pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
dev: Rc<Dev<A>>,
dev_id: dev_t,
priviledged: bool,
active: Arc<AtomicBool>,
old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
handler: Option<RefCell<Box<DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
logger: ::slog::Logger,
}
pub(in crate::backend::drm) struct Dev<A: AsRawFd + 'static>(A);
pub(in crate::backend::drm) struct Dev<A: AsRawFd + 'static> {
fd: A,
priviledged: bool,
active: Arc<AtomicBool>,
old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
logger: ::slog::Logger,
}
impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
self.fd.as_raw_fd()
}
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}
impl<A: AsRawFd + 'static> Drop for Dev<A> {
fn drop(&mut self) {
info!(self.logger, "Dropping device: {:?}", self.dev_path());
if self.active.load(Ordering::SeqCst) {
let old_state = self.old_state.clone();
for (handle, (info, connectors)) in old_state {
if let Err(err) = crtc::set(
&*self,
handle,
info.fb(),
&connectors,
info.position(),
info.mode(),
) {
error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
}
}
}
if self.priviledged {
if let Err(err) = self.drop_master() {
error!(self.logger, "Failed to drop drm master state. Error: {}", err);
}
}
}
}
impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
/// Create a new `LegacyDrmDevice` from an open drm node
@ -53,47 +82,43 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
L: Into<Option<::slog::Logger>>,
{
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));
info!(log, "DrmDevice initializing");
let dev_id = fstat(dev.as_raw_fd())
.chain_err(|| ErrorKind::UnableToGetDeviceId)?
.st_rdev;
let mut drm = LegacyDrmDevice {
// Open the drm device and create a context based on that
dev: Rc::new(Dev(dev)),
dev_id,
let active = Arc::new(AtomicBool::new(true));
let mut dev = Dev {
fd: dev,
priviledged: true,
active: Arc::new(AtomicBool::new(true)),
old_state: HashMap::new(),
backends: Rc::new(RefCell::new(HashMap::new())),
handler: None,
active: active.clone(),
logger: log.clone(),
};
info!(log, "DrmDevice initializing");
// we want to modeset, so we better be the master, if we run via a tty session
if drm.set_master().is_err() {
if dev.set_master().is_err() {
warn!(log, "Unable to become drm master, assuming unpriviledged mode");
drm.priviledged = false;
dev.priviledged = false;
};
let res_handles = ControlDevice::resource_handles(&drm).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path()))
let res_handles = ControlDevice::resource_handles(&dev).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", dev.dev_path()))
})?;
for &con in res_handles.connectors() {
let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path()))
let con_info = connector::Info::load_from_device(&dev, con).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading connector info on {:?}", dev.dev_path()))
})?;
if let Some(enc) = con_info.current_encoder() {
let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path()))
let enc_info = encoder::Info::load_from_device(&dev, enc).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", dev.dev_path()))
})?;
if let Some(crtc) = enc_info.current_crtc() {
let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", drm.dev_path()))
let info = crtc::Info::load_from_device(&dev, crtc).chain_err(|| {
ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", dev.dev_path()))
})?;
drm.old_state
dev.old_state
.entry(crtc)
.or_insert((info, Vec::new()))
.1
@ -101,14 +126,22 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
}
}
}
Ok(drm)
Ok(LegacyDrmDevice {
// Open the drm device and create a context based on that
dev: Rc::new(dev),
dev_id,
active,
backends: Rc::new(RefCell::new(HashMap::new())),
handler: None,
logger: log.clone(),
})
}
}
impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmDevice<A> {
fn as_raw_fd(&self) -> RawFd {
self.dev.0.as_raw_fd()
self.dev.as_raw_fd()
}
}
@ -247,28 +280,6 @@ impl<A: AsRawFd + 'static> RawDevice for LegacyDrmDevice<A> {
impl<A: AsRawFd + 'static> Drop for LegacyDrmDevice<A> {
fn drop(&mut self) {
self.backends.borrow_mut().clear();
if Rc::strong_count(&self.dev) > 1 {
panic!("Pending DrmBackends. You need to free all backends before the DrmDevice gets destroyed");
}
if self.active.load(Ordering::SeqCst) {
for (handle, (info, connectors)) in self.old_state.drain() {
if let Err(err) = crtc::set(
&*self.dev,
handle,
info.fb(),
&connectors,
info.position(),
info.mode(),
) {
error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
}
}
}
if self.priviledged {
if let Err(err) = self.drop_master() {
error!(self.logger, "Failed to drop drm master state. Error: {}", err);
}
}
self.clear_handler();
}
}

View File

@ -18,7 +18,6 @@ pub struct LegacyDrmDeviceObserver<A: AsRawFd + 'static> {
dev_id: dev_t,
priviledged: bool,
active: Arc<AtomicBool>,
old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
logger: ::slog::Logger,
}
@ -28,9 +27,8 @@ impl<A: AsRawFd + 'static> AsSessionObserver<LegacyDrmDeviceObserver<A>> for Leg
LegacyDrmDeviceObserver {
dev: Rc::downgrade(&self.dev),
dev_id: self.dev_id,
old_state: self.old_state.clone(),
active: self.active.clone(),
priviledged: self.priviledged,
priviledged: self.dev.priviledged,
backends: Rc::downgrade(&self.backends),
logger: self.logger.clone(),
}
@ -50,18 +48,6 @@ impl<A: AsRawFd + 'static> SessionObserver for LegacyDrmDeviceObserver<A> {
let _ = crtc::clear_cursor(&*device, surface.crtc);
}
}
for (handle, &(ref info, ref connectors)) in &self.old_state {
if let Err(err) = crtc::set(
&*device,
*handle,
info.fb(),
connectors,
info.position(),
info.mode(),
) {
error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
}
}
}
self.active.store(false, Ordering::SeqCst);
if self.priviledged {