use std::marker::PhantomData;
use linux_api::signal::Signal;
use shadow_shim_helper_rs::emulated_time::EmulatedTime;
use shadow_shim_helper_rs::util::SendPointer;
use crate::cshadow;
use crate::host::descriptor::OpenFile;
use crate::host::host::Host;
use crate::host::syscall::Trigger;
#[derive(Debug, PartialEq, Eq)]
pub struct SyscallConditionRef<'a> {
c_ptr: SendPointer<cshadow::SysCallCondition>,
_phantom: PhantomData<&'a ()>,
}
impl<'a> SyscallConditionRef<'a> {
pub unsafe fn borrow_from_c(ptr: *mut cshadow::SysCallCondition) -> Self {
assert!(!ptr.is_null());
Self {
c_ptr: unsafe { SendPointer::new(ptr) },
_phantom: PhantomData,
}
}
pub fn active_file(&self) -> Option<&OpenFile> {
let file_ptr = unsafe { cshadow::syscallcondition_getActiveFile(self.c_ptr.ptr()) };
if file_ptr.is_null() {
return None;
}
Some(unsafe { file_ptr.as_ref() }.unwrap())
}
pub fn timeout(&self) -> Option<EmulatedTime> {
let timeout = unsafe { cshadow::syscallcondition_getTimeout(self.c_ptr.ptr()) };
EmulatedTime::from_c_emutime(timeout)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SyscallConditionRefMut<'a> {
condition: SyscallConditionRef<'a>,
}
impl<'a> SyscallConditionRefMut<'a> {
pub unsafe fn borrow_from_c(ptr: *mut cshadow::SysCallCondition) -> Self {
assert!(!ptr.is_null());
Self {
condition: unsafe { SyscallConditionRef::borrow_from_c(ptr) },
}
}
pub fn set_active_file(&mut self, file: OpenFile) {
let file_ptr = Box::into_raw(Box::new(file));
unsafe { cshadow::syscallcondition_setActiveFile(self.condition.c_ptr.ptr(), file_ptr) };
}
pub fn wakeup_for_signal(&mut self, host: &Host, signal: Signal) -> bool {
unsafe {
cshadow::syscallcondition_wakeupForSignal(
self.condition.c_ptr.ptr(),
host,
signal.into(),
)
}
}
pub fn set_timeout(&mut self, timeout: Option<EmulatedTime>) {
let timeout = EmulatedTime::to_c_emutime(timeout);
unsafe { cshadow::syscallcondition_setTimeout(self.c_ptr.ptr(), timeout) };
}
}
impl<'a> std::ops::Deref for SyscallConditionRefMut<'a> {
type Target = SyscallConditionRef<'a>;
fn deref(&self) -> &Self::Target {
&self.condition
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SyscallCondition {
condition: Option<SyscallConditionRefMut<'static>>,
}
impl SyscallCondition {
pub unsafe fn consume_from_c(ptr: *mut cshadow::SysCallCondition) -> Self {
assert!(!ptr.is_null());
Self {
condition: Some(unsafe { SyscallConditionRefMut::borrow_from_c(ptr) }),
}
}
pub fn new(trigger: Trigger) -> Self {
SyscallCondition {
condition: Some(unsafe {
SyscallConditionRefMut::borrow_from_c(cshadow::syscallcondition_new(trigger.into()))
}),
}
}
pub fn new_from_wakeup_time(abs_wakeup_time: EmulatedTime) -> Self {
SyscallCondition {
condition: Some(unsafe {
SyscallConditionRefMut::borrow_from_c(cshadow::syscallcondition_newWithAbsTimeout(
EmulatedTime::to_c_emutime(Some(abs_wakeup_time)),
))
}),
}
}
pub fn into_inner(mut self) -> *mut cshadow::SysCallCondition {
let condition = self.condition.take().unwrap();
condition.c_ptr.ptr()
}
}
impl Drop for SyscallCondition {
fn drop(&mut self) {
if let Some(condition) = &self.condition {
if !condition.c_ptr.ptr().is_null() {
unsafe { cshadow::syscallcondition_unref(condition.c_ptr.ptr()) }
}
}
}
}
impl std::ops::Deref for SyscallCondition {
type Target = SyscallConditionRefMut<'static>;
fn deref(&self) -> &Self::Target {
self.condition.as_ref().unwrap()
}
}
impl std::ops::DerefMut for SyscallCondition {
fn deref_mut(&mut self) -> &mut Self::Target {
self.condition.as_mut().unwrap()
}
}