Skip to main content

shadow_rs/host/
host.rs

1//! An emulated Linux system.
2
3use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
4use std::collections::BTreeMap;
5use std::ffi::{CStr, CString, OsString};
6use std::net::{Ipv4Addr, SocketAddrV4};
7use std::ops::{Deref, DerefMut};
8use std::os::unix::prelude::OsStringExt;
9use std::path::{Path, PathBuf};
10use std::sync::{Arc, Mutex};
11
12use asm_util::tsc::Tsc;
13use atomic_refcell::AtomicRefCell;
14use linux_api::signal::{Signal, siginfo_t};
15use log::{debug, trace};
16use logger::LogLevel;
17use once_cell::unsync::OnceCell;
18use rand::SeedableRng;
19use rand_xoshiro::Xoshiro256PlusPlus;
20use shadow_shim_helper_rs::HostId;
21use shadow_shim_helper_rs::emulated_time::EmulatedTime;
22use shadow_shim_helper_rs::explicit_drop::ExplicitDropper;
23use shadow_shim_helper_rs::rootedcell::Root;
24use shadow_shim_helper_rs::rootedcell::cell::RootedCell;
25use shadow_shim_helper_rs::rootedcell::rc::RootedRc;
26use shadow_shim_helper_rs::rootedcell::refcell::RootedRefCell;
27use shadow_shim_helper_rs::shim_shmem::{HostShmem, HostShmemProtected, ManagerShmem};
28use shadow_shim_helper_rs::simulation_time::SimulationTime;
29use shadow_shmem::allocator::ShMemBlock;
30use vasi_sync::scmutex::SelfContainedMutexGuard;
31
32use crate::core::configuration::{ProcessFinalState, QDiscMode};
33use crate::core::sim_config::PcapConfig;
34use crate::core::work::event::{Event, EventData};
35use crate::core::work::event_queue::EventQueue;
36use crate::core::work::task::TaskRef;
37use crate::core::worker::Worker;
38use crate::cshadow;
39use crate::host::descriptor::socket::abstract_unix_ns::AbstractUnixNamespace;
40use crate::host::descriptor::socket::inet::InetSocket;
41use crate::host::fcntl_lock_table::FcntlLockTable;
42use crate::host::futex_table::FutexTable;
43use crate::host::network::interface::{FifoPacketPriority, NetworkInterface, PcapOptions};
44use crate::host::network::namespace::NetworkNamespace;
45use crate::host::process::Process;
46use crate::host::thread::{Thread, ThreadId};
47use crate::network::PacketDevice;
48use crate::network::relay::{RateLimit, Relay};
49use crate::network::router::Router;
50use crate::utility;
51#[cfg(feature = "perf_timers")]
52use crate::utility::perf_timer::PerfTimer;
53
54pub struct HostParameters {
55    pub id: HostId,
56    pub node_seed: u64,
57    // TODO: Remove when we don't need C compatibility.
58    // Already storing as a String in HostInfo.
59    pub hostname: CString,
60    pub node_id: u32,
61    pub ip_addr: libc::in_addr_t,
62    pub sim_end_time: EmulatedTime,
63    pub requested_bw_down_bits: u64,
64    pub requested_bw_up_bits: u64,
65    pub cpu_frequency: u64,
66    pub cpu_threshold: Option<SimulationTime>,
67    pub cpu_precision: Option<SimulationTime>,
68    pub log_level: LogLevel,
69    pub pcap_config: Option<PcapConfig>,
70    pub qdisc: QDiscMode,
71    pub init_sock_recv_buf_size: u64,
72    pub autotune_recv_buf: bool,
73    pub init_sock_send_buf_size: u64,
74    pub autotune_send_buf: bool,
75    pub native_tsc_frequency: u64,
76    pub model_unblocked_syscall_latency: bool,
77    pub max_unapplied_cpu_latency: SimulationTime,
78    pub unblocked_syscall_latency: SimulationTime,
79    pub unblocked_vdso_latency: SimulationTime,
80    pub strace_logging_options: Option<FmtOptions>,
81    pub shim_log_level: LogLevel,
82    pub use_new_tcp: bool,
83    pub use_syscall_counters: bool,
84}
85
86use super::cpu::Cpu;
87use super::process::ProcessId;
88use super::syscall::formatter::FmtOptions;
89
90/// Immutable information about the Host.
91#[derive(Debug, Clone)]
92pub struct HostInfo {
93    pub id: HostId,
94    pub name: String,
95    pub default_ip: Ipv4Addr,
96    pub log_level: Option<log::LevelFilter>,
97}
98
99/// A simulated Host.
100pub struct Host {
101    // Store immutable info in an Arc, that we can safely clone into the
102    // ShadowLogger. We can't use a RootedRc here since this needs to be cloned
103    // into the logger thread, which doesn't have access to the Host's Root.
104    //
105    // TODO: Get rid of the enclosing OnceCell and initialize at the point where
106    // the necessary data is available.
107    info: OnceCell<Arc<HostInfo>>,
108
109    // Inside the Host "object graph", we use the Host's Root for RootedRc and RootedRefCells,
110    // giving us atomic-free refcounting and checked borrowing.
111    //
112    // This makes the Host !Sync.
113    root: Root,
114
115    event_queue: Arc<Mutex<EventQueue>>,
116
117    random: RefCell<Xoshiro256PlusPlus>,
118
119    // The upstream router that will queue packets until we can receive them.
120    // This only applies to the internet interface; the localhost interface
121    // does not receive packets from a router.
122    router: RefCell<Router>,
123
124    // Forwards packets out from our internet interface to the router.
125    relay_inet_out: Arc<Relay>,
126    // Forwards packets from the router in to our internet interface.
127    relay_inet_in: Arc<Relay>,
128    // Forwards packets from the localhost interface back to itself.
129    relay_loopback: Arc<Relay>,
130
131    // map address to futex objects
132    futex_table: RefCell<FutexTable>,
133
134    // track fcntl locks
135    fcntl_lock_table: RefCell<FcntlLockTable>,
136
137    #[cfg(feature = "perf_timers")]
138    execution_timer: RefCell<PerfTimer>,
139
140    pub params: HostParameters,
141
142    cpu: RefCell<Cpu>,
143
144    net_ns: NetworkNamespace,
145
146    // Store as a CString so that we can return a borrowed pointer to C code
147    // instead of having to allocate a new string.
148    //
149    // TODO: Remove `data_dir_path_cstring` once we can remove `host_getDataPath`. (Or maybe don't
150    // store it at all)
151    data_dir_path: PathBuf,
152    data_dir_path_cstring: CString,
153
154    // virtual process and event id counter
155    thread_id_counter: Cell<libc::pid_t>,
156    event_id_counter: Cell<u64>,
157    packet_id_counter: Cell<u64>,
158
159    // Enables us to sort objects deterministically based on their creation order.
160    determinism_sequence_counter: Cell<u64>,
161
162    // track the order in which the application sent us application data
163    packet_priority_counter: Cell<FifoPacketPriority>,
164
165    // Owned pointers to processes.
166    processes: RefCell<BTreeMap<ProcessId, RootedRc<RootedRefCell<Process>>>>,
167
168    tsc: Tsc,
169    // Cached lock for shim_shmem. `[Host::shmem_lock]` uses unsafe code to give it
170    // a 'static lifetime.
171    // SAFETY:
172    // * This field must not outlive `shim_shmem`. We achieve this by:
173    //   * Declaring this field before `shim_shmem` so that it's dropped before
174    //   it.
175    //   * We never expose the guard itself via non-unsafe interfaces. e.g.  our
176    //   safe interfaces don't allow access to the guard itself, nor to the
177    //   internal data with a lifetime that could outlive `self` (and thereby
178    //   `shim_shmem`).
179    shim_shmem_lock:
180        RefCell<Option<UnsafeCell<SelfContainedMutexGuard<'static, HostShmemProtected>>>>,
181    // Shared memory with the shim.
182    //
183    // SAFETY: The data inside HostShmem::protected aliases shim_shmem_lock when
184    // the latter is held.  Even when holding `&mut self` or `self`, if
185    // `shim_shmem_lock` is held we must avoid invalidating it, e.g. by
186    // `std::mem::replace`.
187    //
188    // Note though that we're already prevented from creating another reference
189    // to the data inside `HostShmem::protected` through this field, since
190    // `self.shim_shmem...protected.lock()` will fail if the lock is already
191    // held.
192    shim_shmem: UnsafeCell<ShMemBlock<'static, HostShmem>>,
193
194    in_notify_socket_has_packets: RootedCell<bool>,
195
196    /// Paths to be added to LD_PRELOAD of managed processes.
197    preload_paths: Arc<Vec<PathBuf>>,
198}
199
200/// Host must be `Send`.
201impl crate::utility::IsSend for Host {}
202
203// TODO: use derive(Debug) if/when all fields implement Debug.
204impl std::fmt::Debug for Host {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        f.debug_struct("Host")
207            .field("info", &self.info)
208            .finish_non_exhaustive()
209    }
210}
211
212impl Host {
213    pub fn new(
214        params: HostParameters,
215        host_root_path: &Path,
216        raw_cpu_freq_khz: u64,
217        manager_shmem: &ShMemBlock<ManagerShmem>,
218        preload_paths: Arc<Vec<PathBuf>>,
219    ) -> Self {
220        #[cfg(feature = "perf_timers")]
221        let execution_timer = RefCell::new(PerfTimer::new_started());
222
223        let root = Root::new();
224        let random = RefCell::new(Xoshiro256PlusPlus::seed_from_u64(params.node_seed));
225        let cpu = RefCell::new(Cpu::new(
226            params.cpu_frequency,
227            raw_cpu_freq_khz,
228            params.cpu_threshold,
229            params.cpu_precision,
230        ));
231        let data_dir_path = Self::make_data_dir_path(&params.hostname, host_root_path);
232        let data_dir_path_cstring = utility::pathbuf_to_nul_term_cstring(data_dir_path.clone());
233
234        let host_shmem = HostShmem::new(
235            params.id,
236            params.model_unblocked_syscall_latency,
237            params.max_unapplied_cpu_latency,
238            params.unblocked_syscall_latency,
239            params.unblocked_vdso_latency,
240            nix::unistd::getpid().as_raw(),
241            params.native_tsc_frequency,
242            params.shim_log_level,
243            manager_shmem,
244        );
245        let shim_shmem = UnsafeCell::new(shadow_shmem::allocator::shmalloc(host_shmem));
246
247        // Process IDs start at 1000
248        let thread_id_counter = Cell::new(1000);
249        let event_id_counter = Cell::new(0);
250        let packet_id_counter = Cell::new(0);
251        let determinism_sequence_counter = Cell::new(0);
252        // Packet priorities start at 1. "0" is used for control packets.
253        let packet_priority_counter = Cell::new(1);
254        let tsc = Tsc::new(params.native_tsc_frequency);
255
256        std::fs::create_dir_all(&data_dir_path).unwrap();
257
258        // Register using the param hints.
259        // We already checked that the addresses are available, so fail if they are not.
260
261        let public_ip: Ipv4Addr = u32::from_be(params.ip_addr).into();
262
263        let pcap_options = params.pcap_config.as_ref().map(|x| PcapOptions {
264            path: data_dir_path.clone(),
265            capture_size_bytes: x.capture_size.try_into().unwrap(),
266        });
267
268        let net_ns = NetworkNamespace::new(public_ip, pcap_options, params.qdisc);
269
270        // Packets that are not for localhost or our public ip go to the router.
271        // Use `Ipv4Addr::UNSPECIFIED` for the router to encode this for our
272        // routing table logic inside of `Host::get_packet_device()`.
273        let router = Router::new(Ipv4Addr::UNSPECIFIED);
274        let relay_inet_out = Relay::new(
275            RateLimit::BytesPerSecond(params.requested_bw_up_bits / 8),
276            net_ns.internet.borrow().get_address(),
277        );
278        let relay_inet_in = Relay::new(
279            RateLimit::BytesPerSecond(params.requested_bw_down_bits / 8),
280            router.get_address(),
281        );
282        let relay_loopback = Relay::new(
283            RateLimit::Unlimited,
284            net_ns.localhost.borrow().get_address(),
285        );
286
287        let in_notify_socket_has_packets = RootedCell::new(&root, false);
288
289        let res = Self {
290            info: OnceCell::new(),
291            root,
292            event_queue: Arc::new(Mutex::new(EventQueue::new())),
293            params,
294            router: RefCell::new(router),
295            relay_inet_out: Arc::new(relay_inet_out),
296            relay_inet_in: Arc::new(relay_inet_in),
297            relay_loopback: Arc::new(relay_loopback),
298            futex_table: RefCell::new(FutexTable::new()),
299            fcntl_lock_table: RefCell::new(FcntlLockTable::new()),
300            random,
301            shim_shmem,
302            shim_shmem_lock: RefCell::new(None),
303            cpu,
304            net_ns,
305            data_dir_path,
306            data_dir_path_cstring,
307            thread_id_counter,
308            event_id_counter,
309            packet_id_counter,
310            packet_priority_counter,
311            determinism_sequence_counter,
312            tsc,
313            processes: RefCell::new(BTreeMap::new()),
314            #[cfg(feature = "perf_timers")]
315            execution_timer,
316            in_notify_socket_has_packets,
317            preload_paths,
318        };
319
320        res.stop_execution_timer();
321
322        debug!(
323            concat!(
324                "Setup host id '{:?}'",
325                " name '{name}'",
326                " with seed {seed},",
327                " {bw_up_kiBps} bwUpKiBps,",
328                " {bw_down_kiBps} bwDownKiBps,",
329                " {init_sock_send_buf_size} initSockSendBufSize,",
330                " {init_sock_recv_buf_size} initSockRecvBufSize, ",
331                " {cpu_frequency:?} cpuFrequency, ",
332                " {cpu_threshold:?} cpuThreshold, ",
333                " {cpu_precision:?} cpuPrecision"
334            ),
335            res.id(),
336            name = res.info().name,
337            seed = res.params.node_seed,
338            bw_up_kiBps = res.bw_up_kiBps(),
339            bw_down_kiBps = res.bw_down_kiBps(),
340            init_sock_send_buf_size = res.params.init_sock_send_buf_size,
341            init_sock_recv_buf_size = res.params.init_sock_recv_buf_size,
342            cpu_frequency = res.params.cpu_frequency,
343            cpu_threshold = res.params.cpu_threshold,
344            cpu_precision = res.params.cpu_precision,
345        );
346
347        res
348    }
349
350    pub fn root(&self) -> &Root {
351        &self.root
352    }
353
354    fn make_data_dir_path(hostname: &CStr, host_root_path: &Path) -> PathBuf {
355        let hostname: OsString = { OsString::from_vec(hostname.to_bytes().to_vec()) };
356
357        let mut data_dir_path = PathBuf::new();
358        data_dir_path.push(host_root_path);
359        data_dir_path.push(&hostname);
360        data_dir_path
361    }
362
363    pub fn data_dir_path(&self) -> &Path {
364        &self.data_dir_path
365    }
366
367    pub fn add_application(
368        &self,
369        start_time: SimulationTime,
370        shutdown_time: Option<SimulationTime>,
371        shutdown_signal: nix::sys::signal::Signal,
372        plugin_name: CString,
373        plugin_path: CString,
374        argv: Vec<CString>,
375        envv: Vec<CString>,
376        pause_for_debugging: bool,
377        expected_final_state: ProcessFinalState,
378    ) {
379        debug_assert!(shutdown_time.is_none() || shutdown_time.unwrap() > start_time);
380
381        // Schedule spawning the process.
382        let task = TaskRef::new(move |host| {
383            // We can't move out of these captured variables, since TaskRef takes
384            // a Fn, not a FnOnce.
385            // TODO: Add support for FnOnce?
386            let envv = envv.clone();
387            let argv = argv.clone();
388
389            let process = Process::spawn(
390                host,
391                plugin_name.clone(),
392                &plugin_path,
393                argv,
394                envv,
395                pause_for_debugging,
396                host.params.strace_logging_options,
397                expected_final_state,
398            )
399            .unwrap_or_else(|e| panic!("Failed to initialize application {plugin_name:?}: {e:?}"));
400            let (process_id, thread_id) = {
401                let process = process.borrow(host.root());
402                (process.id(), process.thread_group_leader_id())
403            };
404            host.processes.borrow_mut().insert(process_id, process);
405
406            if let Some(shutdown_time) = shutdown_time {
407                let task = TaskRef::new(move |host| {
408                    let Some(process) = host.process_borrow(process_id) else {
409                        debug!(
410                            "Can't send shutdown signal to process {process_id}; it no longer exists"
411                        );
412                        return;
413                    };
414                    let process = process.borrow(host.root());
415                    let siginfo = siginfo_t::new_for_kill(
416                        Signal::try_from(shutdown_signal as i32).unwrap(),
417                        1,
418                        0,
419                    );
420                    process.signal(host, None, &siginfo);
421                });
422                host.schedule_task_at_emulated_time(
423                    task,
424                    EmulatedTime::SIMULATION_START + shutdown_time,
425                );
426            }
427
428            host.resume(process_id, thread_id);
429        });
430        self.schedule_task_at_emulated_time(task, EmulatedTime::SIMULATION_START + start_time);
431    }
432
433    pub fn add_and_schedule_forked_process(
434        &self,
435        host: &Host,
436        process: RootedRc<RootedRefCell<Process>>,
437    ) {
438        let (process_id, thread_id) = {
439            let process = process.borrow(&self.root);
440            (process.id(), process.thread_group_leader_id())
441        };
442        host.processes.borrow_mut().insert(process_id, process);
443        // Schedule process to run.
444        let task = TaskRef::new(move |host| {
445            host.resume(process_id, thread_id);
446        });
447        self.schedule_task_with_delay(task, SimulationTime::ZERO);
448    }
449
450    pub fn resume(&self, pid: ProcessId, tid: ThreadId) {
451        let Some(processrc) = self
452            .process_borrow(pid)
453            .map(|p| RootedRc::clone(&p, &self.root))
454        else {
455            trace!("{pid:?} doesn't exist");
456            return;
457        };
458        let processrc = ExplicitDropper::new(processrc, |p| {
459            p.explicit_drop_recursive(&self.root, self);
460        });
461        let died;
462        let is_orphan;
463        {
464            Worker::set_active_process(&processrc);
465            let process = processrc.borrow(self.root());
466            process.resume(self, tid);
467            Worker::clear_active_process();
468            let zombie_state = process.borrow_as_zombie();
469            if let Some(zombie) = zombie_state {
470                died = true;
471                is_orphan = zombie.reaper(self).is_none();
472            } else {
473                died = false;
474                is_orphan = false;
475            }
476        };
477
478        if !died {
479            return;
480        }
481
482        let child_pids: Vec<_> = self
483            .processes
484            .borrow()
485            .iter()
486            .filter_map(|(other_pid, processrc)| {
487                let process = processrc.borrow(&self.root);
488                if process.parent_id() != pid {
489                    // Not a child of the current process
490                    return None;
491                }
492                Some(*other_pid)
493            })
494            .collect();
495
496        // Reparent children, and collect IDs of children that are dead. Deliver
497        // parent-death signals before reparenting so the old parent PID is still
498        // reported in the siginfo payload. Since Shadow tracks parentage at the
499        // process level, this models parent-process death rather than the more
500        // specific parent-thread behavior Linux implements.
501        let mut orphaned_zombie_pids: Vec<ProcessId> = Vec::new();
502        for child_pid in child_pids {
503            let parent_death_signal = {
504                let Some(processrc) = self.process_borrow(child_pid) else {
505                    continue;
506                };
507                let process = processrc.borrow(&self.root);
508                process.parent_death_signal()
509            };
510
511            if let Some(signal) = parent_death_signal {
512                let siginfo = siginfo_t::new_for_kill(signal, pid.into(), 0);
513                let Some(processrc) = self.process_borrow(child_pid) else {
514                    continue;
515                };
516                let process = processrc.borrow(&self.root);
517                process.signal(self, None, &siginfo);
518            }
519
520            let is_zombie = {
521                let Some(processrc) = self.process_borrow(child_pid) else {
522                    continue;
523                };
524                let process = processrc.borrow(&self.root);
525                process.set_parent_id(ProcessId::INIT);
526                process.borrow_as_zombie().is_some()
527            };
528            if is_zombie {
529                orphaned_zombie_pids.push(child_pid);
530            }
531        }
532
533        // Process we ran is a zombie; is it also an orphan?
534        debug_assert!(died);
535        if is_orphan {
536            orphaned_zombie_pids.push(pid);
537        }
538
539        // Free orphaned zombies.
540        let mut processes = self.processes.borrow_mut();
541        for pid in orphaned_zombie_pids {
542            trace!("Dropping orphan zombie process {pid:?}");
543            let processrc = processes.remove(&pid).unwrap();
544            RootedRc::explicit_drop_recursive(processrc, &self.root, self);
545        }
546    }
547
548    #[track_caller]
549    pub fn process_borrow(
550        &self,
551        id: ProcessId,
552    ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Process>>> + '_> {
553        Ref::filter_map(self.processes.borrow(), |processes| processes.get(&id)).ok()
554    }
555
556    /// Remove the given process from the Host, if it exists.
557    #[track_caller]
558    pub fn process_remove(&self, id: ProcessId) -> Option<RootedRc<RootedRefCell<Process>>> {
559        self.processes.borrow_mut().remove(&id)
560    }
561
562    /// Borrow the set of processes. Generally this should only be used to
563    /// iterate over the set of processes. e.g. fetching a specific process
564    /// should be done via via `process_borrow`.
565    // TODO: It would be preferable to return an iterator instead of the
566    // collection itself. There has to be an intermediate object though since we
567    // need both the borrowed map of processes, and an iterator that borrows
568    // from that. I suppose we could create an abstract "Iterator factory" and
569    // return that here instead of exposing BTreeMap type.
570    #[track_caller]
571    pub fn processes_borrow(
572        &self,
573    ) -> impl Deref<Target = BTreeMap<ProcessId, RootedRc<RootedRefCell<Process>>>> + '_ {
574        self.processes.borrow()
575    }
576
577    pub fn cpu_borrow(&self) -> impl Deref<Target = Cpu> + '_ {
578        self.cpu.borrow()
579    }
580
581    pub fn cpu_borrow_mut(&self) -> impl DerefMut<Target = Cpu> + '_ {
582        self.cpu.borrow_mut()
583    }
584
585    /// Information about the Host. Made available as an Arc for cheap cloning
586    /// into, e.g. Worker and ShadowLogger. When there's no need to clone the
587    /// Arc, generally prefer the top-level `Host` methods for accessing this
588    /// information, which are likely to be more stable.
589    pub fn info(&self) -> &Arc<HostInfo> {
590        self.info.get_or_init(|| {
591            Arc::new(HostInfo {
592                id: self.id(),
593                name: self.params.hostname.to_str().unwrap().to_owned(),
594                default_ip: self.default_ip(),
595                log_level: self.log_level(),
596            })
597        })
598    }
599
600    pub fn id(&self) -> HostId {
601        self.params.id
602    }
603
604    pub fn name(&self) -> &str {
605        &self.info().name
606    }
607
608    pub fn default_ip(&self) -> Ipv4Addr {
609        self.net_ns.default_ip
610    }
611
612    pub fn abstract_unix_namespace(
613        &self,
614    ) -> impl Deref<Target = Arc<AtomicRefCell<AbstractUnixNamespace>>> + '_ {
615        &self.net_ns.unix
616    }
617
618    pub fn log_level(&self) -> Option<log::LevelFilter> {
619        let level = self.params.log_level;
620        log_c2rust::c_to_rust_log_level(level).map(|l| l.to_level_filter())
621    }
622
623    #[track_caller]
624    pub fn upstream_router_borrow_mut(&self) -> impl DerefMut<Target = Router> + '_ {
625        self.router.borrow_mut()
626    }
627
628    #[track_caller]
629    pub fn network_namespace_borrow(&self) -> impl Deref<Target = NetworkNamespace> + '_ {
630        &self.net_ns
631    }
632
633    #[track_caller]
634    pub fn futextable_borrow(&self) -> impl Deref<Target = FutexTable> + '_ {
635        self.futex_table.borrow()
636    }
637
638    #[track_caller]
639    pub fn futextable_borrow_mut(&self) -> impl DerefMut<Target = FutexTable> + '_ {
640        self.futex_table.borrow_mut()
641    }
642
643    #[track_caller]
644    pub fn fcntl_lock_table_borrow(&self) -> impl Deref<Target = FcntlLockTable> + '_ {
645        self.fcntl_lock_table.borrow()
646    }
647
648    #[track_caller]
649    pub fn fcntl_lock_table_borrow_mut(&self) -> impl DerefMut<Target = FcntlLockTable> + '_ {
650        self.fcntl_lock_table.borrow_mut()
651    }
652
653    #[allow(non_snake_case)]
654    pub fn bw_up_kiBps(&self) -> u64 {
655        self.params.requested_bw_up_bits / (8 * 1024)
656    }
657
658    #[allow(non_snake_case)]
659    pub fn bw_down_kiBps(&self) -> u64 {
660        self.params.requested_bw_down_bits / (8 * 1024)
661    }
662
663    /// Returns `None` if there is no such interface.
664    ///
665    /// Panics if we have shut down.
666    pub fn interface_borrow_mut(
667        &self,
668        addr: Ipv4Addr,
669    ) -> Option<impl DerefMut<Target = NetworkInterface> + '_> {
670        self.net_ns.interface_borrow_mut(addr)
671    }
672
673    /// Returns `None` if there is no such interface.
674    ///
675    /// Panics if we have shut down.
676    pub fn interface_borrow(
677        &self,
678        addr: Ipv4Addr,
679    ) -> Option<impl Deref<Target = NetworkInterface> + '_> {
680        self.net_ns.interface_borrow(addr)
681    }
682
683    #[track_caller]
684    pub fn random_mut(&self) -> impl DerefMut<Target = Xoshiro256PlusPlus> + '_ {
685        self.random.borrow_mut()
686    }
687
688    pub fn get_new_event_id(&self) -> u64 {
689        let res = self.event_id_counter.get();
690        self.event_id_counter.set(res + 1);
691        res
692    }
693
694    pub fn get_new_thread_id(&self) -> ThreadId {
695        let res = self.thread_id_counter.get();
696        self.thread_id_counter.set(res + 1);
697        res.try_into().unwrap()
698    }
699
700    pub fn get_new_packet_id(&self) -> u64 {
701        let res = self.packet_id_counter.get();
702        self.packet_id_counter.set(res + 1);
703        res
704    }
705
706    pub fn get_next_deterministic_sequence_value(&self) -> u64 {
707        let res = self.determinism_sequence_counter.get();
708        self.determinism_sequence_counter.set(res + 1);
709        res
710    }
711
712    pub fn get_next_packet_priority(&self) -> FifoPacketPriority {
713        let res = self.packet_priority_counter.get();
714        self.packet_priority_counter
715            .set(res.checked_add(1).unwrap());
716        res
717    }
718
719    pub fn continue_execution_timer(&self) {
720        #[cfg(feature = "perf_timers")]
721        self.execution_timer.borrow_mut().start();
722    }
723
724    pub fn stop_execution_timer(&self) {
725        #[cfg(feature = "perf_timers")]
726        self.execution_timer.borrow_mut().stop();
727    }
728
729    pub fn schedule_task_at_emulated_time(&self, task: TaskRef, t: EmulatedTime) -> bool {
730        let event = Event::new_local(task, t, self);
731        self.push_local_event(event)
732    }
733
734    pub fn schedule_task_with_delay(&self, task: TaskRef, t: SimulationTime) -> bool {
735        self.schedule_task_at_emulated_time(task, Worker::current_time().unwrap() + t)
736    }
737
738    pub fn event_queue(&self) -> &Arc<Mutex<EventQueue>> {
739        &self.event_queue
740    }
741
742    pub fn push_local_event(&self, event: Event) -> bool {
743        if event.time() >= self.params.sim_end_time {
744            return false;
745        }
746        self.event_queue.lock().unwrap().push(event);
747        true
748    }
749
750    /// Shut down the host. This should be called while `Worker` has the active host set.
751    pub fn shutdown(&self) {
752        self.continue_execution_timer();
753
754        debug!("shutting down host {}", self.name());
755
756        // the network namespace object needs to be cleaned up before it's dropped
757        self.net_ns.cleanup();
758
759        assert!(self.processes.borrow().is_empty());
760
761        self.stop_execution_timer();
762        #[cfg(feature = "perf_timers")]
763        debug!(
764            "host '{}' has been shut down, total execution time was {:?}",
765            self.name(),
766            self.execution_timer.borrow().elapsed()
767        );
768    }
769
770    pub fn free_all_applications(&self) {
771        trace!("start freeing applications for host '{}'", self.name());
772        let processes = std::mem::take(&mut *self.processes.borrow_mut());
773        for (_id, processrc) in processes.into_iter() {
774            let processrc = ExplicitDropper::new(processrc, |p| {
775                p.explicit_drop_recursive(self.root(), self);
776            });
777            Worker::set_active_process(&processrc);
778            let process = processrc.borrow(self.root());
779            process.stop(self);
780            Worker::clear_active_process();
781            // Reparent to Shadow/INIT, since the original parent is or is
782            // about to be dead.
783            process.set_parent_id(ProcessId::INIT);
784        }
785        trace!("done freeing application for host '{}'", self.name());
786    }
787
788    pub fn execute(&self, until: EmulatedTime) {
789        loop {
790            let mut event = {
791                let mut event_queue = self.event_queue.lock().unwrap();
792                match event_queue.next_event_time() {
793                    Some(t) if t < until => {}
794                    _ => break,
795                };
796                event_queue.pop().unwrap()
797            };
798
799            {
800                let mut cpu = self.cpu.borrow_mut();
801                cpu.update_time(event.time());
802                let cpu_delay = cpu.delay();
803                if cpu_delay > SimulationTime::ZERO {
804                    trace!("event blocked on CPU, rescheduled for {cpu_delay:?} from now");
805
806                    // reschedule the event after the CPU delay time
807                    event.set_time(event.time() + cpu_delay);
808                    self.push_local_event(event);
809
810                    // want to continue pushing back events until we reach the delay time
811                    continue;
812                }
813            }
814
815            // run the event
816            Worker::set_current_time(event.time());
817            self.continue_execution_timer();
818            match event.data() {
819                EventData::Packet(data) => {
820                    self.upstream_router_borrow_mut()
821                        .route_incoming_packet(data.into());
822                    self.notify_router_has_packets();
823                }
824                EventData::Local(data) => TaskRef::from(data).execute(self),
825            }
826            self.stop_execution_timer();
827            Worker::clear_current_time();
828        }
829    }
830
831    pub fn next_event_time(&self) -> Option<EmulatedTime> {
832        self.event_queue.lock().unwrap().next_event_time()
833    }
834
835    /// The unprotected part of the Host's shared memory.
836    ///
837    /// Do not try to take the lock of [`HostShmem::protected`] directly.
838    /// Instead use [`Host::lock_shmem`], [`Host::shim_shmem_lock_borrow`], and
839    /// [`Host::shim_shmem_lock_borrow_mut`].
840    pub fn shim_shmem(&self) -> &ShMemBlock<'static, HostShmem> {
841        unsafe { &*self.shim_shmem.get() }
842    }
843
844    /// Returns the specified thread if it exists. If you already have the thread's process,
845    /// [`Process::thread_borrow`] may be more efficient.
846    pub fn thread_cloned_rc(
847        &self,
848        virtual_tid: ThreadId,
849    ) -> Option<RootedRc<RootedRefCell<Thread>>> {
850        for process in self.processes.borrow().values() {
851            let process = process.borrow(self.root());
852            if let Some(thread) = process.thread_borrow(virtual_tid) {
853                return Some(RootedRc::clone(&*thread, self.root()));
854            };
855        }
856
857        None
858    }
859
860    /// Returns `true` if the host has a process that contains the specified thread.
861    pub fn has_thread(&self, virtual_tid: ThreadId) -> bool {
862        for process in self.processes.borrow().values() {
863            let process = process.borrow(self.root());
864            if process.thread_borrow(virtual_tid).is_some() {
865                return true;
866            }
867        }
868
869        false
870    }
871
872    /// Locks the Host's shared memory, caching the lock internally.
873    ///
874    /// Dropping the Host before calling [`Host::unlock_shmem`] will panic.
875    ///
876    /// TODO: Consider removing this API once we don't need to cache the lock for the C API.
877    pub fn lock_shmem(&self) {
878        // We're extending this lifetime to extend the lifetime of `lock`, below, without
879        // having to `transmute` the type itself.
880        //
881        // SAFETY:
882        // * We ensure that `self.shim_shmem_lock` doesn't outlive `self.shim_shmem`.
883        //   See SAFETY requirements on Self::shim_shmem_lock itself.
884        // * We never mutate `self.shim_shmem` nor borrow the internals of
885        //   `self.shim_shmem.protected` while the lock is held, since that would
886        //   conflict with the cached guard's mutable reference.
887        // * `ShMemBlock` guarantees that its data doesn't move even if the block does.
888        //    So moving `shim_shmem` (e.g. by moving `self`) doesn't invalidate the lock.
889        let shim_shmem: &'static ShMemBlock<HostShmem> =
890            unsafe { self.shim_shmem.get().as_ref().unwrap() };
891        let lock = shim_shmem.protected().lock();
892        let prev = self
893            .shim_shmem_lock
894            .borrow_mut()
895            .replace(UnsafeCell::new(lock));
896        assert!(prev.is_none());
897    }
898
899    /// Panics if there is still an outstanding reference returned by
900    /// `shim_shmem_lock_borrow` or `shim_shmem_lock_borrow_mut`.
901    pub fn unlock_shmem(&self) {
902        let prev = self.shim_shmem_lock.borrow_mut().take();
903        assert!(prev.is_some());
904    }
905
906    pub fn shim_shmem_lock_borrow(&self) -> Option<impl Deref<Target = HostShmemProtected> + '_> {
907        Ref::filter_map(self.shim_shmem_lock.borrow(), |l| {
908            l.as_ref().map(|l| {
909                // SAFETY: Returned object holds a checked borrow of the lock;
910                // trying to release the lock before the returned object is
911                // dropped will result in a panic.
912                let guard = unsafe { &*l.get() };
913                guard.deref()
914            })
915        })
916        .ok()
917    }
918
919    pub fn shim_shmem_lock_borrow_mut(
920        &self,
921    ) -> Option<impl DerefMut<Target = HostShmemProtected> + '_> {
922        RefMut::filter_map(self.shim_shmem_lock.borrow_mut(), |l| {
923            l.as_ref().map(|l| {
924                // SAFETY: Returned object holds a checked borrow of the lock;
925                // trying to release the lock before the returned object is
926                // dropped will result in a panic.
927                let guard = unsafe { &mut *l.get() };
928                guard.deref_mut()
929            })
930        })
931        .ok()
932    }
933
934    /// Timestamp Counter emulation for this Host. It ticks at the same rate as
935    /// the native Timestamp Counter, if we were able to find it.
936    pub fn tsc(&self) -> &Tsc {
937        &self.tsc
938    }
939
940    /// Get the packet device that handles packets for the given address. This
941    /// could be the source device from which we forward packets, or the device
942    /// that will receive and process packets with a given destination address.
943    /// In the latter case, if the packet destination is not on this host, we
944    /// return the router to route it to the correct host.
945    pub fn get_packet_device(&self, address: Ipv4Addr) -> Ref<'_, dyn PacketDevice> {
946        if address == Ipv4Addr::LOCALHOST {
947            self.net_ns.localhost.borrow()
948        } else if address == self.default_ip() {
949            self.net_ns.internet.borrow()
950        } else {
951            self.router.borrow()
952        }
953    }
954
955    /// Call to trigger the forwarding of packets from the router to the network
956    /// interface.
957    pub fn notify_router_has_packets(&self) {
958        self.relay_inet_in.notify(self);
959    }
960
961    /// Call to trigger the forwarding of packets from the network interface to
962    /// the next hop (either back to the network interface for loopback, or up to
963    /// the router for internet-bound packets).
964    ///
965    /// WARNING: This is not reentrant. Do not allow this to be called recursively. Nothing in
966    /// `add_data_source()` or `notify()` can call back into this method. This includes any socket
967    /// code called in any indirect way from here.
968    pub fn notify_socket_has_packets(&self, addr: Ipv4Addr, socket: &InetSocket) {
969        if self.in_notify_socket_has_packets.replace(&self.root, true) {
970            panic!("Recursively calling host.notify_socket_has_packets()");
971        }
972
973        if let Some(iface) = self.interface_borrow(addr) {
974            iface.add_data_source(socket);
975            match addr {
976                Ipv4Addr::LOCALHOST => self.relay_loopback.notify(self),
977                _ => self.relay_inet_out.notify(self),
978            };
979        }
980
981        self.in_notify_socket_has_packets.set(&self.root, false);
982    }
983
984    /// Returns the Session ID for the given process group ID, if it exists.
985    pub fn process_session_id_of_group_id(&self, group_id: ProcessId) -> Option<ProcessId> {
986        let processes = self.processes.borrow();
987        for processrc in processes.values() {
988            let process = processrc.borrow(&self.root);
989            if process.group_id() == group_id {
990                return Some(process.session_id());
991            }
992        }
993        None
994    }
995
996    /// Paths of libraries that should be preloaded into managed processes.
997    pub fn preload_paths(&self) -> &[PathBuf] {
998        &self.preload_paths
999    }
1000}
1001
1002impl Drop for Host {
1003    fn drop(&mut self) {
1004        // Validate that the shmem lock isn't held, which would potentially
1005        // violate the SAFETY argument in `lock_shmem`. (AFAIK Rust makes no formal
1006        // guarantee about the order in which fields are dropped)
1007        assert!(self.shim_shmem_lock.borrow().is_none());
1008    }
1009}
1010
1011mod export {
1012    use std::{os::raw::c_char, time::Duration};
1013
1014    use libc::{in_addr_t, in_port_t};
1015    use rand::{Rng, RngExt};
1016    use shadow_shim_helper_rs::shim_shmem;
1017
1018    use super::*;
1019    use crate::cshadow::{CEmulatedTime, CSimulationTime};
1020    use crate::network::packet::IanaProtocol;
1021
1022    #[unsafe(no_mangle)]
1023    pub unsafe extern "C-unwind" fn host_execute(hostrc: *const Host, until: CEmulatedTime) {
1024        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1025        let until = EmulatedTime::from_c_emutime(until).unwrap();
1026        hostrc.execute(until)
1027    }
1028
1029    #[unsafe(no_mangle)]
1030    pub unsafe extern "C-unwind" fn host_nextEventTime(hostrc: *const Host) -> CEmulatedTime {
1031        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1032        EmulatedTime::to_c_emutime(hostrc.next_event_time())
1033    }
1034
1035    #[unsafe(no_mangle)]
1036    pub unsafe extern "C-unwind" fn host_getNewPacketID(hostrc: *const Host) -> u64 {
1037        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1038        hostrc.get_new_packet_id()
1039    }
1040
1041    #[unsafe(no_mangle)]
1042    pub unsafe extern "C-unwind" fn host_freeAllApplications(hostrc: *const Host) {
1043        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1044        hostrc.free_all_applications()
1045    }
1046
1047    #[unsafe(no_mangle)]
1048    pub unsafe extern "C-unwind" fn host_getID(hostrc: *const Host) -> HostId {
1049        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1050        hostrc.id()
1051    }
1052
1053    /// SAFETY: The returned pointer belongs to Host, and is invalidated when
1054    /// `host` is moved or freed.
1055    #[unsafe(no_mangle)]
1056    pub unsafe extern "C-unwind" fn host_getTsc(host: *const Host) -> *const Tsc {
1057        let hostrc = unsafe { host.as_ref().unwrap() };
1058        hostrc.tsc()
1059    }
1060
1061    #[unsafe(no_mangle)]
1062    pub unsafe extern "C-unwind" fn host_getName(hostrc: *const Host) -> *const c_char {
1063        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1064        hostrc.params.hostname.as_ptr()
1065    }
1066
1067    #[unsafe(no_mangle)]
1068    pub unsafe extern "C-unwind" fn host_getDefaultIP(hostrc: *const Host) -> in_addr_t {
1069        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1070        let ip = hostrc.default_ip();
1071        u32::from(ip).to_be()
1072    }
1073
1074    #[unsafe(no_mangle)]
1075    pub unsafe extern "C-unwind" fn host_getNextPacketPriority(
1076        hostrc: *const Host,
1077    ) -> FifoPacketPriority {
1078        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1079        hostrc.get_next_packet_priority()
1080    }
1081
1082    #[unsafe(no_mangle)]
1083    pub unsafe extern "C-unwind" fn host_autotuneReceiveBuffer(hostrc: *const Host) -> bool {
1084        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1085        hostrc.params.autotune_recv_buf
1086    }
1087
1088    #[unsafe(no_mangle)]
1089    pub unsafe extern "C-unwind" fn host_autotuneSendBuffer(hostrc: *const Host) -> bool {
1090        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1091        hostrc.params.autotune_send_buf
1092    }
1093
1094    #[unsafe(no_mangle)]
1095    pub unsafe extern "C-unwind" fn host_getConfiguredRecvBufSize(hostrc: *const Host) -> u64 {
1096        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1097        hostrc.params.init_sock_recv_buf_size
1098    }
1099
1100    #[unsafe(no_mangle)]
1101    pub unsafe extern "C-unwind" fn host_getConfiguredSendBufSize(hostrc: *const Host) -> u64 {
1102        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1103        hostrc.params.init_sock_send_buf_size
1104    }
1105
1106    #[unsafe(no_mangle)]
1107    pub unsafe extern "C-unwind" fn host_getUpstreamRouter(hostrc: *const Host) -> *mut Router {
1108        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1109        &mut *hostrc.upstream_router_borrow_mut()
1110    }
1111
1112    #[unsafe(no_mangle)]
1113    pub unsafe extern "C-unwind" fn host_get_bw_down_kiBps(hostrc: *const Host) -> u64 {
1114        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1115        hostrc.bw_down_kiBps()
1116    }
1117
1118    #[unsafe(no_mangle)]
1119    pub unsafe extern "C-unwind" fn host_get_bw_up_kiBps(hostrc: *const Host) -> u64 {
1120        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1121        hostrc.bw_up_kiBps()
1122    }
1123
1124    /// SAFETY: The returned pointer is owned by the Host, and will be invalidated when
1125    /// the Host is destroyed, and possibly when it is otherwise moved or mutated.
1126    #[unsafe(no_mangle)]
1127    pub unsafe extern "C-unwind" fn host_getDataPath(hostrc: *const Host) -> *const c_char {
1128        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1129        hostrc.data_dir_path_cstring.as_ptr()
1130    }
1131
1132    #[unsafe(no_mangle)]
1133    pub unsafe extern "C-unwind" fn host_disassociateInterface(
1134        hostrc: *const Host,
1135        c_protocol: cshadow::ProtocolType,
1136        bind_ip: in_addr_t,
1137        bind_port: in_port_t,
1138        peer_ip: in_addr_t,
1139        peer_port: in_port_t,
1140    ) {
1141        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1142
1143        let bind_ip = Ipv4Addr::from(u32::from_be(bind_ip));
1144        let peer_ip = Ipv4Addr::from(u32::from_be(peer_ip));
1145        let bind_port = u16::from_be(bind_port);
1146        let peer_port = u16::from_be(peer_port);
1147
1148        let bind_addr = SocketAddrV4::new(bind_ip, bind_port);
1149        let peer_addr = SocketAddrV4::new(peer_ip, peer_port);
1150
1151        let protocol = IanaProtocol::from(c_protocol);
1152
1153        // associate the interfaces corresponding to bind_addr with socket
1154        hostrc
1155            .net_ns
1156            .disassociate_interface(protocol, bind_addr, peer_addr);
1157    }
1158
1159    #[unsafe(no_mangle)]
1160    pub unsafe extern "C-unwind" fn host_getRandomFreePort(
1161        hostrc: *const Host,
1162        c_protocol: cshadow::ProtocolType,
1163        interface_ip: in_addr_t,
1164        peer_ip: in_addr_t,
1165        peer_port: in_port_t,
1166    ) -> in_port_t {
1167        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1168
1169        let interface_ip = Ipv4Addr::from(u32::from_be(interface_ip));
1170        let peer_addr = SocketAddrV4::new(
1171            Ipv4Addr::from(u32::from_be(peer_ip)),
1172            u16::from_be(peer_port),
1173        );
1174
1175        let protocol = IanaProtocol::from(c_protocol);
1176
1177        hostrc
1178            .net_ns
1179            .get_random_free_port(
1180                protocol,
1181                interface_ip,
1182                peer_addr,
1183                hostrc.random.borrow_mut().deref_mut(),
1184            )
1185            .unwrap_or(0)
1186            .to_be()
1187    }
1188
1189    /// Returns a pointer to the Host's FutexTable.
1190    ///
1191    /// SAFETY: The returned pointer belongs to and is synchronized by the Host,
1192    /// and is invalidated when the Host is no longer accessible to the current
1193    /// thread, or something else accesses its FutexTable.
1194    #[unsafe(no_mangle)]
1195    pub unsafe extern "C-unwind" fn host_getFutexTable(hostrc: *const Host) -> *mut FutexTable {
1196        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1197        &mut *hostrc.futextable_borrow_mut()
1198    }
1199
1200    /// Returns the specified process, or NULL if it doesn't exist.
1201    #[unsafe(no_mangle)]
1202    pub unsafe extern "C-unwind" fn host_getProcess(
1203        host: *const Host,
1204        virtual_pid: libc::pid_t,
1205    ) -> *const Process {
1206        let host = unsafe { host.as_ref().unwrap() };
1207        let virtual_pid = ProcessId::try_from(virtual_pid).unwrap();
1208        host.process_borrow(virtual_pid)
1209            .map(|x| std::ptr::from_ref(&*x.borrow(host.root())))
1210            .unwrap_or(std::ptr::null_mut())
1211    }
1212
1213    /// Returns the specified thread, or NULL if it doesn't exist.
1214    /// If you already have the thread's Process*, `process_getThread` may be more
1215    /// efficient.
1216    ///
1217    /// # Safety
1218    ///
1219    /// The pointer should not be accessed from threads other than the calling thread,
1220    /// or after `host` is no longer active on the current thread.
1221    #[unsafe(no_mangle)]
1222    pub unsafe extern "C-unwind" fn host_getThread(
1223        host: *const Host,
1224        virtual_tid: libc::pid_t,
1225    ) -> *const Thread {
1226        let host = unsafe { host.as_ref().unwrap() };
1227        let tid = ThreadId::try_from(virtual_tid).unwrap();
1228        for process in host.processes.borrow().values() {
1229            let process = process.borrow(host.root());
1230            if let Some(thread) = process.thread_borrow(tid) {
1231                // We're returning a pointer to the Thread itself after having
1232                // dropped the borrow. In addition to the requirements noted for the calling code,
1233                // this could cause soundness issues if we were to ever take mutable borrows of
1234                // the RootedRefCell, since it'd be difficult to ensure we didn't have any simultaneous
1235                // additional references from dereferencing a C pointer.
1236                //
1237                // TODO: Add a variant of RootedRefCell that doesn't allow
1238                // mutable borrows, use it for Thread, and name that type
1239                // explicitly here to ensure a compilation error if the type is
1240                // changed again to one that would allow mutable references.
1241                let thread = thread.borrow(host.root());
1242                return std::ptr::from_ref(&*thread);
1243            };
1244        }
1245        std::ptr::null_mut()
1246    }
1247
1248    /// Returns the lock, or panics if the lock isn't held by Shadow.
1249    ///
1250    /// Generally the lock can and should be held when Shadow is running, and *not*
1251    /// held when any of the host's managed threads are running (leaving it available
1252    /// to be taken by the shim). While this can be a little fragile to ensure
1253    /// properly, debug builds detect if we get it wrong (e.g. we try accessing
1254    /// protected data without holding the lock, or the shim tries to take the lock
1255    /// but can't).
1256    ///
1257    /// SAFETY: The returned pointer is invalidated when the memory is unlocked, e.g.
1258    /// via `host_unlockShimShmemLock`.
1259    #[unsafe(no_mangle)]
1260    pub unsafe extern "C-unwind" fn host_getShimShmemLock(
1261        hostrc: *const Host,
1262    ) -> *mut shim_shmem::export::ShimShmemHostLock {
1263        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1264        let mut opt_lock = hostrc.shim_shmem_lock.borrow_mut();
1265        let lock = opt_lock.as_mut().unwrap();
1266        // SAFETY: The caller is responsible for not accessing the returned pointer
1267        // after the lock has been released.
1268        unsafe { lock.get().as_mut().unwrap().deref_mut() }
1269    }
1270
1271    /// Take the host's shared memory lock. See `host_getShimShmemLock`.
1272    #[unsafe(no_mangle)]
1273    pub unsafe extern "C-unwind" fn host_lockShimShmemLock(hostrc: *const Host) {
1274        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1275        hostrc.lock_shmem()
1276    }
1277
1278    /// Release the host's shared memory lock. See `host_getShimShmemLock`.
1279    #[unsafe(no_mangle)]
1280    pub unsafe extern "C-unwind" fn host_unlockShimShmemLock(hostrc: *const Host) {
1281        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1282        hostrc.unlock_shmem()
1283    }
1284
1285    /// Returns the next value and increments our monotonically increasing
1286    /// determinism sequence counter. The resulting values can be sorted to
1287    /// established a deterministic ordering, which can be useful when iterating
1288    /// items that are otherwise inconsistently ordered (e.g. hash table iterators).
1289    #[unsafe(no_mangle)]
1290    pub unsafe extern "C-unwind" fn host_getNextDeterministicSequenceValue(
1291        hostrc: *const Host,
1292    ) -> u64 {
1293        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1294        hostrc.get_next_deterministic_sequence_value()
1295    }
1296
1297    /// Schedule a task for this host at time 'time'.
1298    #[unsafe(no_mangle)]
1299    pub unsafe extern "C-unwind" fn host_scheduleTaskAtEmulatedTime(
1300        hostrc: *const Host,
1301        task: *mut TaskRef,
1302        time: CEmulatedTime,
1303    ) -> bool {
1304        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1305        let task = unsafe { task.as_ref().unwrap().clone() };
1306        let time = EmulatedTime::from_c_emutime(time).unwrap();
1307        hostrc.schedule_task_at_emulated_time(task, time)
1308    }
1309
1310    /// Schedule a task for this host at a time 'nanoDelay' from now,.
1311    #[unsafe(no_mangle)]
1312    pub unsafe extern "C-unwind" fn host_scheduleTaskWithDelay(
1313        hostrc: *const Host,
1314        task: *mut TaskRef,
1315        delay: CSimulationTime,
1316    ) -> bool {
1317        let hostrc = unsafe { hostrc.as_ref().unwrap() };
1318        let task = unsafe { task.as_ref().unwrap().clone() };
1319        let delay = SimulationTime::from_c_simtime(delay).unwrap();
1320        hostrc.schedule_task_with_delay(task, delay)
1321    }
1322
1323    #[unsafe(no_mangle)]
1324    pub unsafe extern "C-unwind" fn host_rngDouble(host: *const Host) -> f64 {
1325        let host = unsafe { host.as_ref().unwrap() };
1326        host.random_mut().random()
1327    }
1328
1329    /// Fills the buffer with pseudo-random bytes.
1330    #[unsafe(no_mangle)]
1331    pub extern "C-unwind" fn host_rngNextNBytes(host: *const Host, buf: *mut u8, len: usize) {
1332        let host = unsafe { host.as_ref().unwrap() };
1333        let buf = unsafe { std::slice::from_raw_parts_mut(buf, len) };
1334        host.random_mut().fill_bytes(buf);
1335    }
1336
1337    #[unsafe(no_mangle)]
1338    pub extern "C-unwind" fn host_paramsCpuFrequencyHz(host: *const Host) -> u64 {
1339        let host = unsafe { host.as_ref().unwrap() };
1340        host.params.cpu_frequency
1341    }
1342
1343    #[unsafe(no_mangle)]
1344    pub extern "C-unwind" fn host_addDelayNanos(host: *const Host, delay_nanos: u64) {
1345        let host = unsafe { host.as_ref().unwrap() };
1346        let delay = Duration::from_nanos(delay_nanos);
1347        host.cpu.borrow_mut().add_delay(delay);
1348    }
1349
1350    #[unsafe(no_mangle)]
1351    pub unsafe extern "C-unwind" fn host_socketWantsToSend(
1352        hostrc: *const Host,
1353        socket: *const InetSocket,
1354        addr: in_addr_t,
1355    ) {
1356        let host = unsafe { hostrc.as_ref().unwrap() };
1357        let socket = unsafe { socket.as_ref().unwrap() };
1358        let addr = u32::from_be(addr).into();
1359        host.notify_socket_has_packets(addr, socket);
1360    }
1361
1362    #[unsafe(no_mangle)]
1363    pub unsafe extern "C-unwind" fn host_continue(
1364        host: *const Host,
1365        pid: libc::pid_t,
1366        tid: libc::pid_t,
1367    ) {
1368        let host = unsafe { host.as_ref().unwrap() };
1369        host.resume(pid.try_into().unwrap(), tid.try_into().unwrap())
1370    }
1371}