Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

Change CallbackGuard to require explicit destruction #250

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/main_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,18 @@ impl MainContext {

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
let func: &RefCell<Box<FnMut() + 'static>> = transmute(func);
(&mut *func.borrow_mut())();
guard.defuse();

glib_ffi::G_SOURCE_REMOVE
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
Box::<RefCell<Box<FnMut() + 'static>>>::from_raw(ptr as *mut _);
guard.defuse();
}

fn into_raw<F: FnMut() + Send + 'static>(func: F) -> gpointer {
Expand Down
3 changes: 2 additions & 1 deletion src/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
// destroy
Box::<Box<Fn()>>::from_raw(ptr as *mut _);
guard.defuse();
}
44 changes: 26 additions & 18 deletions src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use std::mem::{forget, transmute};
use ffi as glib_ffi;
use ffi::{gboolean, gpointer};
use translate::{from_glib, from_glib_full, FromGlib, ToGlib, ToGlibPtr};
Expand Down Expand Up @@ -53,44 +51,51 @@ impl ToGlib for Continue {
}
}

/// Unwinding propagation guard. Aborts the process if destroyed while
/// panicking.
/// Unwinding propagation guard.
///
/// Aborts the process if the `defuse` method isn't called.
pub struct CallbackGuard(());

impl CallbackGuard {
#[inline]
pub fn new() -> CallbackGuard {
CallbackGuard(())
}

/// Drops this `CallbackGuard` and avoids aborting the process
#[inline]
pub fn defuse(self) {
forget(self);
}
}

impl Default for CallbackGuard {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl Drop for CallbackGuard {
fn drop(&mut self) {
use std::io::stderr;
use std::io::Write;

if thread::panicking() {
let _ = stderr().write(b"Uncaught panic, exiting\n");
process::abort();
}
panic!("`CallbackGuard` dropped without having `defuse` called, \
likely because a function panicked, aborting the process");
}
}

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
(&mut *func.borrow_mut())().to_glib()
let r = (&mut *func.borrow_mut())().to_glib();
guard.defuse();
return r
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
guard.defuse();
}

fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
Expand All @@ -101,14 +106,17 @@ fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline_child_watch(pid: u32, status: i32, func: gpointer) {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
let func: &RefCell<Box<FnMut(u32, i32) + 'static>> = transmute(func);
(&mut *func.borrow_mut())(pid, status)
let r = (&mut *func.borrow_mut())(pid, status);
guard.defuse();
return r
}

unsafe extern "C" fn destroy_closure_child_watch(ptr: gpointer) {
let _guard = CallbackGuard::new();
let guard = CallbackGuard::new();
Box::<RefCell<Box<FnMut(u32, i32) + 'static>>>::from_raw(ptr as *mut _);
guard.defuse();
}

fn into_raw_child_watch<F: FnMut(u32, i32) + Send + 'static>(func: F) -> gpointer {
Expand Down