1use 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 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#[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
100pub struct Host {
102 info: OnceCell<Arc<HostInfo>>,
109
110 root: Root,
115
116 event_queue: Arc<Mutex<EventQueue>>,
117
118 random: RefCell<Xoshiro256PlusPlus>,
119
120 router: RefCell<Router>,
124
125 relay_inet_out: Arc<Relay>,
127 relay_inet_in: Arc<Relay>,
129 relay_loopback: Arc<Relay>,
131
132 futex_table: RefCell<FutexTable>,
134
135 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 data_dir_path: PathBuf,
153 data_dir_path_cstring: CString,
154
155 thread_id_counter: Cell<libc::pid_t>,
157 event_id_counter: Cell<u64>,
158 packet_id_counter: Cell<u64>,
159
160 determinism_sequence_counter: Cell<u64>,
162
163 packet_priority_counter: Cell<FifoPacketPriority>,
165
166 processes: RefCell<BTreeMap<ProcessId, RootedRc<RootedRefCell<Process>>>>,
168
169 tsc: Tsc,
170 shim_shmem_lock:
181 RefCell<Option<UnsafeCell<SelfContainedMutexGuard<'static, HostShmemProtected>>>>,
182 shim_shmem: UnsafeCell<ShMemBlock<'static, HostShmem>>,
194
195 in_notify_socket_has_packets: RootedCell<bool>,
196
197 preload_paths: Arc<Vec<PathBuf>>,
199}
200
201impl crate::utility::IsSend for Host {}
203
204impl 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(¶ms.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 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 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 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 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 let task = TaskRef::new(move |host| {
384 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 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 return None;
492 }
493 Some(*other_pid)
494 })
495 .collect();
496
497 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 debug_assert!(died);
536 if is_orphan {
537 orphaned_zombie_pids.push(pid);
538 }
539
540 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 #[track_caller]
559 pub fn process_remove(&self, id: ProcessId) -> Option<RootedRc<RootedRefCell<Process>>> {
560 self.processes.borrow_mut().remove(&id)
561 }
562
563 #[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 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 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 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 pub fn shutdown(&self) {
753 self.continue_execution_timer();
754
755 debug!("shutting down host {}", self.name());
756
757 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 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 event.set_time(event.time() + cpu_delay);
809 self.push_local_event(event);
810
811 continue;
813 }
814 }
815
816 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 pub fn shim_shmem(&self) -> &ShMemBlock<'static, HostShmem> {
842 unsafe { &*self.shim_shmem.get() }
843 }
844
845 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 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 pub fn lock_shmem(&self) {
879 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 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 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 let guard = unsafe { &mut *l.get() };
929 guard.deref_mut()
930 })
931 })
932 .ok()
933 }
934
935 pub fn tsc(&self) -> &Tsc {
938 &self.tsc
939 }
940
941 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 pub fn notify_router_has_packets(&self) {
959 self.relay_inet_in.notify(self);
960 }
961
962 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 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 pub fn preload_paths(&self) -> &[PathBuf] {
999 &self.preload_paths
1000 }
1001}
1002
1003impl Drop for Host {
1004 fn drop(&mut self) {
1005 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 #[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 #[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 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 #[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 #[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 #[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 let thread = thread.borrow(host.root());
1243 return std::ptr::from_ref(&*thread);
1244 };
1245 }
1246 std::ptr::null_mut()
1247 }
1248
1249 #[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 unsafe { lock.get().as_mut().unwrap().deref_mut() }
1270 }
1271
1272 #[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 #[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 #[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 #[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 #[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 #[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}