#[cfg(not(windows))]
use crate::sys::SIM_notify_on_descriptor;
use crate::{
simics_exception,
sys::{
notify_mode_t, socket_t, SIM_cancel_realtime_event, SIM_notify_on_socket,
SIM_process_pending_work, SIM_process_work, SIM_realtime_event, SIM_register_work,
SIM_run_alone, SIM_run_in_thread, SIM_thread_safe_callback,
},
Result,
};
use raw_cstr::raw_cstr;
use std::{ffi::c_void, ptr::null_mut};
pub type NotifyMode = notify_mode_t;
pub type Socket = socket_t;
extern "C" fn handle_notify_on_descriptor_callback<F>(cb: *mut c_void)
where
F: Fn() + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure()
}
#[cfg(not(windows))]
#[simics_exception]
pub fn notify_on_descriptor<C>(fd: i32, mode: NotifyMode, run_in_thread: bool, callback: Option<C>)
where
C: Fn() + 'static,
{
let callback = if callback.is_none() {
None
} else {
Some(handle_notify_on_descriptor_callback::<C>)
};
unsafe {
SIM_notify_on_descriptor(
fd,
mode,
run_in_thread as i32,
callback
.is_some()
.then_some(handle_notify_on_descriptor_callback::<C>),
callback
.map(|c| {
let callback = Box::new(c);
let callback_box = Box::new(callback);
Box::into_raw(callback_box) as *mut c_void
})
.unwrap_or(null_mut()),
)
}
}
#[simics_exception]
pub fn notify_on_socket<C>(sock: Socket, mode: NotifyMode, run_in_thread: bool, callback: Option<C>)
where
C: Fn() + 'static,
{
let callback = if callback.is_none() {
None
} else {
Some(handle_notify_on_descriptor_callback::<C>)
};
unsafe {
SIM_notify_on_socket(
sock,
mode,
run_in_thread as i32,
callback
.is_some()
.then_some(handle_notify_on_descriptor_callback::<C>),
callback
.map(|c| {
let callback = Box::new(c);
let callback_box = Box::new(callback);
Box::into_raw(callback_box) as *mut c_void
})
.unwrap_or(null_mut()),
)
}
}
extern "C" fn handle_work_callback<F>(cb: *mut c_void)
where
F: FnOnce() + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure()
}
#[simics_exception]
pub fn register_work<F>(work: F)
where
F: FnOnce() + 'static,
{
let work = Box::new(work);
let work_box = Box::new(work);
unsafe {
SIM_register_work(
Some(handle_work_callback::<F>),
Box::into_raw(work_box) as *mut c_void,
)
};
}
extern "C" fn handle_process_work_callback<F>(cb: *mut c_void) -> i32
where
F: FnOnce() -> i32 + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure()
}
#[simics_exception]
pub fn process_work<F>(work: F)
where
F: FnOnce() -> i32 + 'static,
{
let work = Box::new(work);
let work_box = Box::new(work);
unsafe {
SIM_process_work(
Some(handle_process_work_callback::<F>),
Box::into_raw(work_box) as *mut c_void,
)
};
}
#[simics_exception]
pub fn process_pending_work() {
unsafe { SIM_process_pending_work() };
}
extern "C" fn handle_realtime_event_callback<F>(cb: *mut c_void)
where
F: FnOnce() + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure()
}
#[simics_exception]
pub fn realtime_event<F, S>(
delay_ms: u32,
callback: F,
run_in_thread: bool,
description: S,
) -> Result<i64>
where
S: AsRef<str>,
F: FnOnce() + 'static,
{
let callback = Box::new(callback);
let callback_box = Box::new(callback);
Ok(unsafe {
SIM_realtime_event(
delay_ms,
Some(handle_realtime_event_callback::<F>),
Box::into_raw(callback_box) as *mut c_void,
run_in_thread as i32,
raw_cstr(description)?,
)
})
}
#[simics_exception]
pub fn cancel_realtime_event(id: i64) {
unsafe { SIM_cancel_realtime_event(id) };
}
extern "C" fn handle_run_alone_callback<F>(cb: *mut c_void)
where
F: FnOnce() -> Result<()> + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure().expect("Failed while running run_alone callback");
}
#[simics_exception]
pub fn run_alone<F>(cb: F)
where
F: FnOnce() -> Result<()> + 'static,
{
let cb = Box::new(cb);
let cb_box = Box::new(cb);
let cb_raw = Box::into_raw(cb_box);
debug_assert!(
std::mem::size_of_val(&cb_raw) == std::mem::size_of::<*mut std::ffi::c_void>(),
"Pointer is not convertible to *mut c_void"
);
unsafe {
SIM_run_alone(
Some(handle_run_alone_callback::<F>),
cb_raw as *mut _ as *mut c_void,
)
}
}
extern "C" fn handle_thread_safe_callback<F>(cb: *mut c_void)
where
F: FnOnce() + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure()
}
#[simics_exception]
pub fn thread_safe_callback<F>(cb: F)
where
F: FnOnce() + 'static,
{
let cb = Box::new(cb);
let cb_box = Box::new(cb);
let cb_raw = Box::into_raw(cb_box);
debug_assert!(
std::mem::size_of_val(&cb_raw) == std::mem::size_of::<*mut std::ffi::c_void>(),
"Pointer is not convertible to *mut c_void"
);
unsafe {
SIM_thread_safe_callback(
Some(handle_thread_safe_callback::<F>),
cb_raw as *mut _ as *mut c_void,
)
}
}
extern "C" fn handle_in_thread_callback<F>(cb: *mut c_void)
where
F: FnOnce() -> anyhow::Result<()> + 'static,
{
let closure: Box<Box<F>> = unsafe { Box::from_raw(cb as *mut Box<F>) };
closure().expect("Error running in thread callback")
}
#[simics_exception]
pub fn run_in_thread<F>(cb: F)
where
F: FnOnce() -> anyhow::Result<()> + 'static,
{
let cb = Box::new(cb);
let cb_box = Box::new(cb);
let cb_raw = Box::into_raw(cb_box);
debug_assert!(
std::mem::size_of_val(&cb_raw) == std::mem::size_of::<*mut std::ffi::c_void>(),
"Pointer is not convertible to *mut c_void"
);
unsafe {
SIM_run_in_thread(
Some(handle_in_thread_callback::<F>),
cb_raw as *mut _ as *mut c_void,
)
}
}