1
0
Fork 0

Swap out X11 error handling mutex for a RefCell

This commit is contained in:
Robbert van der Helm 2022-03-07 18:52:49 +01:00
parent 0aae938af0
commit 85b6437de8

View file

@ -2,20 +2,20 @@ use std::ffi::CStr;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use x11::xlib; use x11::xlib;
use std::cell::RefCell;
use std::panic::AssertUnwindSafe; use std::panic::AssertUnwindSafe;
use std::sync::Mutex;
thread_local! { thread_local! {
/// Used as part of [`XerrorHandler::handle()`]. When an X11 error occurs during this function, /// Used as part of [`XerrorHandler::handle()`]. When an X11 error occurs during this function,
/// the error gets copied to this mutex after which the program is allowed to resume. The error /// the error gets copied to this RefCell after which the program is allowed to resume. The
/// can then be converted to a regular Rust Result value afterwards. /// error can then be converted to a regular Rust Result value afterwards.
static CURRENT_X11_ERROR: Mutex<Option<xlib::XErrorEvent>> = Mutex::new(None); static CURRENT_X11_ERROR: RefCell<Option<xlib::XErrorEvent>> = RefCell::new(None);
} }
/// A helper struct for safe X11 error handling /// A helper struct for safe X11 error handling
pub struct XErrorHandler<'a> { pub struct XErrorHandler<'a> {
display: *mut xlib::Display, display: *mut xlib::Display,
mutex: &'a Mutex<Option<xlib::XErrorEvent>>, error: &'a RefCell<Option<xlib::XErrorEvent>>,
} }
impl<'a> XErrorHandler<'a> { impl<'a> XErrorHandler<'a> {
@ -25,7 +25,7 @@ impl<'a> XErrorHandler<'a> {
unsafe { unsafe {
xlib::XSync(self.display, 0); xlib::XSync(self.display, 0);
} }
let error = self.mutex.lock().unwrap().take(); let error = self.error.borrow_mut().take();
match error { match error {
None => Ok(()), None => Ok(()),
@ -44,20 +44,16 @@ impl<'a> XErrorHandler<'a> {
// SAFETY: the error pointer should be safe to copy // SAFETY: the error pointer should be safe to copy
let err = *err; let err = *err;
CURRENT_X11_ERROR.with(|mutex| match mutex.lock() { CURRENT_X11_ERROR.with(|error| {
let mut error = error.borrow_mut();
match error.as_mut() {
// If multiple errors occur, keep the first one since that's likely going to be the // If multiple errors occur, keep the first one since that's likely going to be the
// cause of the other errors // cause of the other errors
Ok(mut current_error) if current_error.is_none() => { Some(_) => 1,
*current_error = Some(err); None => {
*error = Some(err);
0 0
} }
Ok(_) => 0,
Err(e) => {
eprintln!(
"[FATAL] raw-gl-context: Failed to lock for X11 Error Handler: {:?}",
e
);
1
} }
}) })
} }
@ -67,13 +63,13 @@ impl<'a> XErrorHandler<'a> {
xlib::XSync(display, 0); xlib::XSync(display, 0);
} }
CURRENT_X11_ERROR.with(|mutex| { CURRENT_X11_ERROR.with(|error| {
// Make sure to clear any errors from the last call to this function // Make sure to clear any errors from the last call to this function
*mutex.lock().unwrap() = None; *error.borrow_mut() = None;
let old_handler = unsafe { xlib::XSetErrorHandler(Some(error_handler)) }; let old_handler = unsafe { xlib::XSetErrorHandler(Some(error_handler)) };
let panic_result = std::panic::catch_unwind(AssertUnwindSafe(|| { let panic_result = std::panic::catch_unwind(AssertUnwindSafe(|| {
let mut h = XErrorHandler { display, mutex: &mutex }; let mut h = XErrorHandler { display, error };
handler(&mut h) handler(&mut h)
})); }));
// Whatever happened, restore old error handler // Whatever happened, restore old error handler