shadow_rs/host/
futex_table.rs1use std::collections::HashMap;
2use std::collections::hash_map::Entry;
3
4use shadow_shim_helper_rs::syscall_types::ManagedPhysicalMemoryAddr;
5use shadow_shim_helper_rs::util::SyncSendPointer;
6
7use crate::cshadow as c;
8use crate::utility::ObjectCounter;
9
10pub struct FutexTable {
12 futexes: HashMap<ManagedPhysicalMemoryAddr, FutexRef>,
15 _counter: ObjectCounter,
16}
17
18impl FutexTable {
19 #[allow(clippy::new_without_default)]
20 pub fn new() -> Self {
21 Self {
22 futexes: HashMap::new(),
23 _counter: ObjectCounter::new("FutexTable"),
24 }
25 }
26
27 pub fn add(&mut self, futex: FutexRef) -> Result<(), FutexRef> {
30 let addr = futex.physical_addr();
31
32 match self.futexes.entry(addr) {
33 Entry::Occupied(_) => Err(futex),
34 Entry::Vacant(x) => {
35 x.insert(futex);
36 Ok(())
37 }
38 }
39 }
40
41 pub fn remove(&mut self, addr: ManagedPhysicalMemoryAddr) -> Option<FutexRef> {
42 self.futexes.remove(&addr)
43 }
44
45 pub fn get(&self, addr: ManagedPhysicalMemoryAddr) -> Option<&FutexRef> {
46 self.futexes.get(&addr)
47 }
48}
49
50#[derive(Debug)]
52pub struct FutexRef(SyncSendPointer<c::Futex>);
53
54impl FutexRef {
55 pub unsafe fn new(ptr: *mut c::Futex) -> Self {
61 debug_assert!(!ptr.is_null());
62 Self(unsafe { SyncSendPointer::new(ptr) })
63 }
64
65 pub fn ptr(&self) -> *mut c::Futex {
66 self.0.ptr()
67 }
68
69 pub fn physical_addr(&self) -> ManagedPhysicalMemoryAddr {
70 unsafe { c::futex_getAddress(self.ptr()) }
71 }
72
73 pub fn wake(&self, num_wakeups: libc::c_uint) -> libc::c_uint {
74 unsafe { c::futex_wake(self.ptr(), num_wakeups) }
75 }
76
77 pub fn listener_count(&self) -> libc::c_uint {
78 unsafe { c::futex_getListenerCount(self.ptr()) }
79 }
80
81 pub fn into_c_ptr(self) -> *mut c::Futex {
87 let ptr = self.ptr();
88 unsafe { c::futex_ref(self.0.ptr()) };
89 ptr
90 }
91}
92
93impl Clone for FutexRef {
94 fn clone(&self) -> Self {
95 unsafe { c::futex_ref(self.0.ptr()) };
96 Self(self.0)
97 }
98}
99
100impl std::ops::Drop for FutexRef {
101 fn drop(&mut self) {
102 unsafe { c::futex_unref(self.0.ptr()) };
103 }
104}
105
106mod export {
107 use super::*;
108
109 #[unsafe(no_mangle)]
111 pub unsafe extern "C-unwind" fn futextable_add(
112 table: *mut FutexTable,
113 futex: *mut c::Futex,
114 ) -> bool {
115 let table = unsafe { table.as_mut() }.unwrap();
116
117 assert!(!futex.is_null());
118 unsafe { c::futex_ref(futex) };
119 let futex = unsafe { FutexRef::new(futex) };
120
121 table.add(futex).is_ok()
122 }
123
124 #[unsafe(no_mangle)]
125 pub unsafe extern "C-unwind" fn futextable_remove(
126 table: *mut FutexTable,
127 addr: ManagedPhysicalMemoryAddr,
128 ) -> bool {
129 let table = unsafe { table.as_mut() }.unwrap();
130 table.remove(addr).is_some()
131 }
132
133 #[unsafe(no_mangle)]
136 pub unsafe extern "C-unwind" fn futextable_get(
137 table: *mut FutexTable,
138 addr: ManagedPhysicalMemoryAddr,
139 ) -> *mut c::Futex {
140 let table = unsafe { table.as_mut() }.unwrap();
141 table
142 .get(addr)
143 .map(|x| x.ptr())
144 .unwrap_or(std::ptr::null_mut())
145 }
146}