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