use mountpoint_s3_crt_sys::*;
struct ShutdownCallbackUserData {
callback: Box<dyn FnOnce()>,
}
pub(crate) fn new_shutdown_callback_options(callback: impl FnOnce() + Send + 'static) -> aws_shutdown_callback_options {
let user_data = ShutdownCallbackUserData {
callback: Box::new(callback),
};
let user_data = Box::leak(Box::new(user_data));
aws_shutdown_callback_options {
shutdown_callback_fn: Some(shutdown_callback),
shutdown_callback_user_data: user_data as *mut ShutdownCallbackUserData as *mut libc::c_void,
}
}
pub(crate) unsafe fn abort_shutdown_callback(callback: aws_shutdown_callback_options) {
assert!(callback.shutdown_callback_fn == Some(shutdown_callback));
let ptr = callback.shutdown_callback_user_data as *mut ShutdownCallbackUserData;
let user_data: Box<ShutdownCallbackUserData> = Box::from_raw(ptr);
std::mem::drop(user_data);
}
unsafe extern "C" fn shutdown_callback(user_data: *mut libc::c_void) {
assert!(!user_data.is_null());
let user_data: Box<ShutdownCallbackUserData> = Box::from_raw(user_data as *mut ShutdownCallbackUserData);
(user_data.callback)();
}
#[cfg(test)]
mod test {
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use super::*;
struct DropSignal(Arc<AtomicBool>);
impl Drop for DropSignal {
fn drop(&mut self) {
self.0.store(true, Ordering::SeqCst);
}
}
#[test]
fn test_abort_shutdown_callback() {
let dropped = Arc::new(AtomicBool::new(false));
let _signal = DropSignal(dropped.clone());
#[allow(unreachable_code)]
let options = new_shutdown_callback_options(|| {
panic!("Should never be called");
std::mem::drop(_signal);
});
unsafe {
abort_shutdown_callback(options);
}
assert!(dropped.load(Ordering::SeqCst));
}
}