shadow_rs/host/syscall/
condition.rs

1use std::marker::PhantomData;
2
3use linux_api::signal::Signal;
4use shadow_shim_helper_rs::emulated_time::EmulatedTime;
5use shadow_shim_helper_rs::util::SendPointer;
6
7use crate::cshadow;
8use crate::host::descriptor::OpenFile;
9use crate::host::host::Host;
10use crate::host::syscall::Trigger;
11
12/// An immutable reference to a syscall condition.
13#[derive(Debug, PartialEq, Eq)]
14pub struct SyscallConditionRef<'a> {
15    c_ptr: SendPointer<cshadow::SysCallCondition>,
16    _phantom: PhantomData<&'a ()>,
17}
18
19// do not define any mutable methods for this type
20impl SyscallConditionRef<'_> {
21    /// Borrows from a C pointer. i.e. doesn't increase the ref count, nor decrease the ref count
22    /// when dropped.
23    ///
24    /// # Safety
25    ///
26    /// `ptr` must point to a valid object that will not be accessed by other threads
27    /// for the lifetime of this object.
28    pub unsafe fn borrow_from_c(ptr: *mut cshadow::SysCallCondition) -> Self {
29        assert!(!ptr.is_null());
30        Self {
31            c_ptr: unsafe { SendPointer::new(ptr) },
32            _phantom: PhantomData,
33        }
34    }
35
36    pub fn active_file(&self) -> Option<&OpenFile> {
37        let file_ptr = unsafe { cshadow::syscallcondition_getActiveFile(self.c_ptr.ptr()) };
38        if file_ptr.is_null() {
39            return None;
40        }
41
42        Some(unsafe { file_ptr.as_ref() }.unwrap())
43    }
44
45    pub fn timeout(&self) -> Option<EmulatedTime> {
46        let timeout = unsafe { cshadow::syscallcondition_getTimeout(self.c_ptr.ptr()) };
47        EmulatedTime::from_c_emutime(timeout)
48    }
49}
50
51/// A mutable reference to a syscall condition.
52#[derive(Debug, PartialEq, Eq)]
53pub struct SyscallConditionRefMut<'a> {
54    condition: SyscallConditionRef<'a>,
55}
56
57// any immutable methods should be implemented on SyscallConditionRef instead
58impl SyscallConditionRefMut<'_> {
59    /// Borrows from a C pointer. i.e. doesn't increase the ref count, nor decrease the ref count
60    /// when dropped.
61    ///
62    /// # Safety
63    ///
64    /// `ptr` must point to a valid object that will not be accessed by other threads
65    /// for the lifetime of this object.
66    pub unsafe fn borrow_from_c(ptr: *mut cshadow::SysCallCondition) -> Self {
67        assert!(!ptr.is_null());
68        Self {
69            condition: unsafe { SyscallConditionRef::borrow_from_c(ptr) },
70        }
71    }
72
73    pub fn set_active_file(&mut self, file: OpenFile) {
74        let file_ptr = Box::into_raw(Box::new(file));
75        unsafe { cshadow::syscallcondition_setActiveFile(self.condition.c_ptr.ptr(), file_ptr) };
76    }
77
78    pub fn wakeup_for_signal(&mut self, host: &Host, signal: Signal) -> bool {
79        unsafe {
80            cshadow::syscallcondition_wakeupForSignal(
81                self.condition.c_ptr.ptr(),
82                host,
83                signal.into(),
84            )
85        }
86    }
87
88    pub fn set_timeout(&mut self, timeout: Option<EmulatedTime>) {
89        let timeout = EmulatedTime::to_c_emutime(timeout);
90        unsafe { cshadow::syscallcondition_setTimeout(self.c_ptr.ptr(), timeout) };
91    }
92}
93
94impl<'a> std::ops::Deref for SyscallConditionRefMut<'a> {
95    type Target = SyscallConditionRef<'a>;
96
97    fn deref(&self) -> &Self::Target {
98        &self.condition
99    }
100}
101
102/// An owned syscall condition.
103#[derive(Debug, PartialEq, Eq)]
104pub struct SyscallCondition {
105    condition: Option<SyscallConditionRefMut<'static>>,
106}
107
108impl SyscallCondition {
109    /// "Steal" from a C pointer. i.e. doesn't increase ref count, but will decrease the ref count
110    /// when dropped.
111    ///
112    /// # Safety
113    ///
114    /// `ptr` must point to a valid object that will not be accessed by other threads
115    /// for the lifetime of this object.
116    pub unsafe fn consume_from_c(ptr: *mut cshadow::SysCallCondition) -> Self {
117        assert!(!ptr.is_null());
118        Self {
119            condition: Some(unsafe { SyscallConditionRefMut::borrow_from_c(ptr) }),
120        }
121    }
122
123    /// Constructor.
124    // TODO: Add support for taking a Timer, ideally after we have a Rust
125    // implementation or wrapper.
126    pub fn new(trigger: Trigger) -> Self {
127        SyscallCondition {
128            condition: Some(unsafe {
129                SyscallConditionRefMut::borrow_from_c(cshadow::syscallcondition_new(trigger.into()))
130            }),
131        }
132    }
133
134    /// Create a new syscall condition that triggers a wakeup on the calling thread only after the
135    /// `abs_wakeup_time` has been reached.
136    ///
137    /// Panics if `abs_wakeup_time` is before the current emulated time.
138    pub fn new_from_wakeup_time(abs_wakeup_time: EmulatedTime) -> Self {
139        SyscallCondition {
140            condition: Some(unsafe {
141                SyscallConditionRefMut::borrow_from_c(cshadow::syscallcondition_newWithAbsTimeout(
142                    EmulatedTime::to_c_emutime(Some(abs_wakeup_time)),
143                ))
144            }),
145        }
146    }
147
148    /// "Steal" the inner pointer without unref'ing it.
149    pub fn into_inner(mut self) -> *mut cshadow::SysCallCondition {
150        let condition = self.condition.take().unwrap();
151        condition.c_ptr.ptr()
152    }
153}
154
155impl Drop for SyscallCondition {
156    fn drop(&mut self) {
157        if let Some(condition) = &self.condition {
158            if !condition.c_ptr.ptr().is_null() {
159                unsafe { cshadow::syscallcondition_unref(condition.c_ptr.ptr()) }
160            }
161        }
162    }
163}
164
165impl std::ops::Deref for SyscallCondition {
166    type Target = SyscallConditionRefMut<'static>;
167
168    fn deref(&self) -> &Self::Target {
169        self.condition.as_ref().unwrap()
170    }
171}
172
173impl std::ops::DerefMut for SyscallCondition {
174    fn deref_mut(&mut self) -> &mut Self::Target {
175        self.condition.as_mut().unwrap()
176    }
177}