1use linux_api::signal::{Signal, sigaction, siginfo_t, sigset_t, stack_t};
2use shadow_shmem::allocator::{ShMemBlock, ShMemBlockSerialized};
3use vasi::VirtualAddressSpaceIndependent;
4use vasi_sync::scmutex::SelfContainedMutex;
5
6use crate::HostId;
7use crate::option::FfiOption;
8use crate::{
9 emulated_time::{AtomicEmulatedTime, EmulatedTime},
10 rootedcell::{Root, refcell::RootedRefCell},
11 simulation_time::SimulationTime,
12};
13
14macro_rules! assert_shmem_safe {
16 ($t:ty, $testfnname:ident) => {
17 static_assertions::assert_impl_all!($t: Sync);
20
21 static_assertions::assert_impl_all!($t: VirtualAddressSpaceIndependent);
24
25 #[deny(improper_ctypes_definitions)]
45 unsafe extern "C-unwind" fn $testfnname(_: $t) {}
46 };
47}
48
49#[derive(VirtualAddressSpaceIndependent)]
50#[repr(C)]
51pub struct NativePreemptionConfig {
52 pub native_duration: linux_api::time::kernel_old_timeval,
58 pub sim_duration: SimulationTime,
61}
62
63#[derive(VirtualAddressSpaceIndependent)]
64#[repr(C)]
65pub struct ManagerShmem {
66 pub log_start_time_micros: i64,
67 pub native_preemption_config: FfiOption<NativePreemptionConfig>,
68 pub emulate_cpuid: bool,
69}
70assert_shmem_safe!(ManagerShmem, _managershmem_test_fn);
71
72#[derive(VirtualAddressSpaceIndependent)]
73#[repr(C)]
74pub struct HostShmem {
75 pub host_id: HostId,
76
77 pub protected: SelfContainedMutex<HostShmemProtected>,
78
79 pub model_unblocked_syscall_latency: bool,
82
83 pub max_unapplied_cpu_latency: SimulationTime,
88
89 pub unblocked_syscall_latency: SimulationTime,
94
95 pub unblocked_vdso_latency: SimulationTime,
100
101 pub shadow_pid: libc::pid_t,
103
104 pub tsc_hz: u64,
106
107 pub sim_time: AtomicEmulatedTime,
109
110 pub shim_log_level: logger::LogLevel,
111
112 pub manager_shmem: ShMemBlockSerialized,
113}
114assert_shmem_safe!(HostShmem, _hostshmem_test_fn);
115
116impl HostShmem {
117 #[allow(clippy::too_many_arguments)]
118 pub fn new(
119 host_id: HostId,
120 model_unblocked_syscall_latency: bool,
121 max_unapplied_cpu_latency: SimulationTime,
122 unblocked_syscall_latency: SimulationTime,
123 unblocked_vdso_latency: SimulationTime,
124 shadow_pid: libc::pid_t,
125 tsc_hz: u64,
126 shim_log_level: ::logger::LogLevel,
127 manager_shmem: &ShMemBlock<ManagerShmem>,
128 ) -> Self {
129 Self {
130 host_id,
131 protected: SelfContainedMutex::new(HostShmemProtected {
132 host_id,
133 root: Root::new(),
134 unapplied_cpu_latency: SimulationTime::ZERO,
135 max_runahead_time: EmulatedTime::MIN,
136 }),
137 model_unblocked_syscall_latency,
138 max_unapplied_cpu_latency,
139 unblocked_syscall_latency,
140 unblocked_vdso_latency,
141 shadow_pid,
142 tsc_hz,
143 sim_time: AtomicEmulatedTime::new(EmulatedTime::MIN),
144 shim_log_level,
145 manager_shmem: manager_shmem.serialize(),
146 }
147 }
148
149 pub fn protected(&self) -> &SelfContainedMutex<HostShmemProtected> {
150 &self.protected
151 }
152}
153
154#[derive(VirtualAddressSpaceIndependent)]
155#[repr(C)]
156pub struct HostShmemProtected {
157 pub host_id: HostId,
158
159 pub root: Root,
160
161 pub unapplied_cpu_latency: SimulationTime,
163
164 pub max_runahead_time: EmulatedTime,
167}
168
169#[derive(VirtualAddressSpaceIndependent)]
170#[repr(C)]
171pub struct ProcessShmem {
172 host_id: HostId,
173
174 pub host_shmem: ShMemBlockSerialized,
176 pub strace_fd: FfiOption<libc::c_int>,
177
178 pub protected: RootedRefCell<ProcessShmemProtected>,
179}
180assert_shmem_safe!(ProcessShmem, _test_processshmem_fn);
181
182impl ProcessShmem {
183 pub fn new(
184 host_root: &Root,
185 host_shmem: ShMemBlockSerialized,
186 host_id: HostId,
187 strace_fd: Option<libc::c_int>,
188 ) -> Self {
189 Self {
190 host_id,
191 host_shmem,
192 strace_fd: strace_fd.into(),
193 protected: RootedRefCell::new(
194 host_root,
195 ProcessShmemProtected {
196 host_id,
197 pending_signals: sigset_t::EMPTY,
198 pending_standard_siginfos: [siginfo_t::default();
199 Signal::STANDARD_MAX.as_i32() as usize],
200 signal_actions: [sigaction::default(); Signal::MAX.as_i32() as usize],
201 },
202 ),
203 }
204 }
205}
206
207#[derive(VirtualAddressSpaceIndependent)]
208#[repr(C)]
209pub struct ProcessShmemProtected {
210 pub host_id: HostId,
211
212 pub pending_signals: sigset_t,
214
215 #[unsafe_assume_virtual_address_space_independent]
219 pending_standard_siginfos: [siginfo_t; Signal::STANDARD_MAX.as_i32() as usize],
220
221 #[unsafe_assume_virtual_address_space_independent]
228 signal_actions: [sigaction; Signal::MAX.as_i32() as usize],
229}
230
231fn signal_idx(signal: Signal) -> usize {
233 (i32::from(signal) - 1) as usize
234}
235
236impl ProcessShmemProtected {
237 pub fn pending_standard_siginfo(&self, signal: Signal) -> Option<&siginfo_t> {
238 if self.pending_signals.has(signal) {
239 Some(&self.pending_standard_siginfos[signal_idx(signal)])
240 } else {
241 None
242 }
243 }
244
245 pub fn set_pending_standard_siginfo(&mut self, signal: Signal, info: &siginfo_t) {
246 assert!(self.pending_signals.has(signal));
247 self.pending_standard_siginfos[signal_idx(signal)] = *info;
248 }
249
250 pub unsafe fn clone_signal_actions(&mut self, src: &Self) {
255 self.signal_actions = src.signal_actions
256 }
257
258 pub unsafe fn signal_action(&self, signal: Signal) -> &sigaction {
264 &self.signal_actions[signal_idx(signal)]
265 }
266
267 pub unsafe fn signal_action_mut(&mut self, signal: Signal) -> &mut sigaction {
273 &mut self.signal_actions[signal_idx(signal)]
274 }
275
276 pub fn clear_pending_signals(&mut self) {
278 self.pending_signals = sigset_t::EMPTY;
279 }
280
281 pub fn take_pending_unblocked_signal(
282 &mut self,
283 thread: &ThreadShmemProtected,
284 ) -> Option<(Signal, siginfo_t)> {
285 let pending_unblocked_signals = self.pending_signals & !thread.blocked_signals;
286 if pending_unblocked_signals.is_empty() {
287 None
288 } else {
289 let signal = pending_unblocked_signals.lowest().unwrap();
290 let info = *self.pending_standard_siginfo(signal).unwrap();
291 self.pending_signals.del(signal);
292 Some((signal, info))
293 }
294 }
295}
296
297#[derive(VirtualAddressSpaceIndependent)]
298#[repr(C)]
299pub struct ThreadShmem {
300 pub host_id: HostId,
301 pub tid: libc::pid_t,
302
303 pub protected: RootedRefCell<ThreadShmemProtected>,
304}
305assert_shmem_safe!(ThreadShmem, _test_threadshmem_fn);
306
307impl ThreadShmem {
308 pub fn new(host: &HostShmemProtected, tid: libc::pid_t) -> Self {
309 Self {
310 host_id: host.host_id,
311 tid,
312 protected: RootedRefCell::new(
313 &host.root,
314 ThreadShmemProtected {
315 host_id: host.host_id,
316 pending_signals: sigset_t::EMPTY,
317 pending_standard_siginfos: [siginfo_t::default();
318 Signal::STANDARD_MAX.as_i32() as usize],
319 blocked_signals: sigset_t::EMPTY,
320 sigaltstack: StackWrapper(stack_t {
321 ss_sp: core::ptr::null_mut(),
322 ss_flags: libc::SS_DISABLE,
323 ss_size: 0,
324 }),
325 },
326 ),
327 }
328 }
329
330 pub fn clone(&self, root: &Root) -> Self {
333 Self {
334 host_id: self.host_id,
335 tid: self.tid,
336 protected: RootedRefCell::new(root, *self.protected.borrow(root)),
337 }
338 }
339}
340
341#[derive(VirtualAddressSpaceIndependent, Copy, Clone)]
342#[repr(C)]
343pub struct ThreadShmemProtected {
344 pub host_id: HostId,
345
346 pub pending_signals: sigset_t,
348
349 #[unsafe_assume_virtual_address_space_independent]
353 pending_standard_siginfos: [siginfo_t; Signal::STANDARD_MAX.as_i32() as usize],
354
355 pub blocked_signals: sigset_t,
359
360 sigaltstack: StackWrapper,
362}
363
364impl ThreadShmemProtected {
365 pub fn pending_standard_siginfo(&self, signal: Signal) -> Option<&siginfo_t> {
366 if self.pending_signals.has(signal) {
367 Some(&self.pending_standard_siginfos[signal_idx(signal)])
368 } else {
369 None
370 }
371 }
372
373 pub fn set_pending_standard_siginfo(&mut self, signal: Signal, info: &siginfo_t) {
374 assert!(self.pending_signals.has(signal));
375 self.pending_standard_siginfos[signal_idx(signal)] = *info;
376 }
377
378 pub unsafe fn sigaltstack(&self) -> &stack_t {
383 &self.sigaltstack.0
384 }
385
386 pub unsafe fn sigaltstack_mut(&mut self) -> &mut stack_t {
392 &mut self.sigaltstack.0
393 }
394
395 pub fn take_pending_unblocked_signal(&mut self) -> Option<(Signal, siginfo_t)> {
396 let pending_unblocked_signals = self.pending_signals & !self.blocked_signals;
397 if pending_unblocked_signals.is_empty() {
398 None
399 } else {
400 let signal = pending_unblocked_signals.lowest().unwrap();
401 let info = *self.pending_standard_siginfo(signal).unwrap();
402 self.pending_signals.del(signal);
403 Some((signal, info))
404 }
405 }
406}
407
408#[derive(Copy, Clone)]
409#[repr(transparent)]
410struct StackWrapper(stack_t);
411
412unsafe impl Send for StackWrapper {}
415
416unsafe impl VirtualAddressSpaceIndependent for StackWrapper {}
419
420pub fn take_pending_unblocked_signal(
422 lock: &HostShmemProtected,
423 process: &ProcessShmem,
424 thread: &ThreadShmem,
425) -> Option<(Signal, siginfo_t)> {
426 let mut thread_protected = thread.protected.borrow_mut(&lock.root);
427 thread_protected
428 .take_pending_unblocked_signal()
429 .or_else(|| {
430 let mut process_protected = process.protected.borrow_mut(&lock.root);
431 process_protected.take_pending_unblocked_signal(&thread_protected)
432 })
433}
434
435pub mod export {
436 use core::sync::atomic::Ordering;
437
438 use bytemuck::TransparentWrapper;
439 use linux_api::signal::{linux_sigaction, linux_sigset_t, linux_stack_t};
440 use vasi_sync::scmutex::SelfContainedMutexGuard;
441
442 use super::*;
443 use crate::{emulated_time::CEmulatedTime, simulation_time::CSimulationTime};
444
445 pub type ShimShmemManager = ManagerShmem;
448 pub type ShimShmemHost = HostShmem;
449 pub type ShimShmemHostLock = HostShmemProtected;
450 pub type ShimShmemProcess = ProcessShmem;
451 pub type ShimShmemThread = ThreadShmem;
452
453 #[unsafe(no_mangle)]
457 pub unsafe extern "C-unwind" fn shimshmemhost_lock(
458 host: *const ShimShmemHost,
459 ) -> *mut ShimShmemHostLock {
460 let host = unsafe { host.as_ref().unwrap() };
461 let mut guard: SelfContainedMutexGuard<ShimShmemHostLock> = host.protected().lock();
462 let lock: &mut ShimShmemHostLock = &mut guard;
463 let lock = core::ptr::from_mut(lock);
464 guard.disconnect();
465 lock
466 }
467
468 #[unsafe(no_mangle)]
472 pub unsafe extern "C-unwind" fn shimshmemhost_unlock(
473 host: *const ShimShmemHost,
474 lock: *mut *mut ShimShmemHostLock,
475 ) {
476 let host = unsafe { host.as_ref().unwrap() };
477 let guard = SelfContainedMutexGuard::reconnect(&host.protected);
478 assert_eq!(host.host_id, guard.host_id);
479
480 let p_lock = unsafe { lock.as_mut().unwrap() };
481 *p_lock = core::ptr::null_mut();
482 }
483
484 #[unsafe(no_mangle)]
488 pub unsafe extern "C-unwind" fn shimshmem_getShadowPid(
489 host_mem: *const ShimShmemHost,
490 ) -> libc::pid_t {
491 let host_mem = unsafe { host_mem.as_ref().unwrap() };
492 host_mem.shadow_pid
493 }
494
495 #[unsafe(no_mangle)]
499 pub unsafe extern "C-unwind" fn shimshmem_getTscHz(host_mem: *const ShimShmemHost) -> u64 {
500 let host_mem = unsafe { host_mem.as_ref().unwrap() };
501 host_mem.tsc_hz
502 }
503
504 #[unsafe(no_mangle)]
508 pub unsafe extern "C-unwind" fn shimshmem_getLogLevel(
509 host_mem: *const ShimShmemHost,
510 ) -> ::logger::LogLevel {
511 let host_mem = unsafe { host_mem.as_ref().unwrap() };
512 host_mem.shim_log_level
513 }
514
515 #[unsafe(no_mangle)]
519 pub unsafe extern "C-unwind" fn shimshmem_getEmulatedTime(
520 host_mem: *const ShimShmemHost,
521 ) -> CEmulatedTime {
522 let host_mem = unsafe { host_mem.as_ref().unwrap() };
523 EmulatedTime::to_c_emutime(Some(host_mem.sim_time.load(Ordering::Relaxed)))
524 }
525
526 #[unsafe(no_mangle)]
530 pub unsafe extern "C-unwind" fn shimshmem_setEmulatedTime(
531 host_mem: *const ShimShmemHost,
532 t: CEmulatedTime,
533 ) {
534 let host_mem = unsafe { host_mem.as_ref().unwrap() };
535 host_mem
536 .sim_time
537 .store(EmulatedTime::from_c_emutime(t).unwrap(), Ordering::Relaxed);
538 }
539
540 #[unsafe(no_mangle)]
544 pub unsafe extern "C-unwind" fn shimshmem_getMaxRunaheadTime(
545 host_mem: *const ShimShmemHostLock,
546 ) -> CEmulatedTime {
547 let host_mem = unsafe { host_mem.as_ref().unwrap() };
548 EmulatedTime::to_c_emutime(Some(host_mem.max_runahead_time))
549 }
550
551 #[unsafe(no_mangle)]
555 pub unsafe extern "C-unwind" fn shimshmem_setMaxRunaheadTime(
556 host_mem: *mut ShimShmemHostLock,
557 t: CEmulatedTime,
558 ) {
559 let host_mem = unsafe { host_mem.as_mut().unwrap() };
560 host_mem.max_runahead_time = EmulatedTime::from_c_emutime(t).unwrap();
561 }
562
563 #[unsafe(no_mangle)]
567 pub unsafe extern "C-unwind" fn shimshmem_getProcessStraceFd(
568 process: *const ShimShmemProcess,
569 ) -> libc::c_int {
570 let process_mem = unsafe { process.as_ref().unwrap() };
571 process_mem.strace_fd.unwrap_or(-1)
572 }
573
574 #[unsafe(no_mangle)]
578 pub unsafe extern "C-unwind" fn shimshmem_getSignalAction(
579 lock: *const ShimShmemHostLock,
580 process: *const ShimShmemProcess,
581 sig: i32,
582 ) -> linux_sigaction {
583 let process_mem = unsafe { process.as_ref().unwrap() };
584 let lock = unsafe { lock.as_ref().unwrap() };
585 let protected = process_mem.protected.borrow(&lock.root);
586 unsafe { sigaction::peel(*protected.signal_action(Signal::try_from(sig).unwrap())) }
587 }
588
589 #[unsafe(no_mangle)]
593 pub unsafe extern "C-unwind" fn shimshmem_setSignalAction(
594 lock: *const ShimShmemHostLock,
595 process: *const ShimShmemProcess,
596 sig: i32,
597 action: *const linux_sigaction,
598 ) {
599 let process_mem = unsafe { process.as_ref().unwrap() };
600 let lock = unsafe { lock.as_ref().unwrap() };
601 let action = sigaction::wrap_ref(unsafe { action.as_ref().unwrap() });
602 let mut protected = process_mem.protected.borrow_mut(&lock.root);
603 unsafe { *protected.signal_action_mut(Signal::try_from(sig).unwrap()) = *action };
604 }
605
606 #[unsafe(no_mangle)]
607 pub extern "C-unwind" fn shimshmemthread_size() -> usize {
608 core::mem::size_of::<ThreadShmem>()
609 }
610
611 #[unsafe(no_mangle)]
615 pub unsafe extern "C-unwind" fn shimshmem_getThreadId(
616 thread: *const ShimShmemThread,
617 ) -> libc::pid_t {
618 let thread_mem = unsafe { thread.as_ref().unwrap() };
619 thread_mem.tid
620 }
621
622 #[unsafe(no_mangle)]
626 pub unsafe extern "C-unwind" fn shimshmem_getBlockedSignals(
627 lock: *const ShimShmemHostLock,
628 thread: *const ShimShmemThread,
629 ) -> linux_sigset_t {
630 let thread_mem = unsafe { thread.as_ref().unwrap() };
631 let lock = unsafe { lock.as_ref().unwrap() };
632 let protected = thread_mem.protected.borrow(&lock.root);
633 sigset_t::peel(protected.blocked_signals)
634 }
635
636 #[unsafe(no_mangle)]
642 pub unsafe extern "C-unwind" fn shimshmem_setBlockedSignals(
643 lock: *const ShimShmemHostLock,
644 thread: *const ShimShmemThread,
645 s: linux_sigset_t,
646 ) {
647 let thread_mem = unsafe { thread.as_ref().unwrap() };
648 let lock = unsafe { lock.as_ref().unwrap() };
649 let mut protected = thread_mem.protected.borrow_mut(&lock.root);
650 protected.blocked_signals = sigset_t::wrap(s);
651 }
652
653 #[unsafe(no_mangle)]
659 pub unsafe extern "C-unwind" fn shimshmem_getSigAltStack(
660 lock: *const ShimShmemHostLock,
661 thread: *const ShimShmemThread,
662 ) -> linux_stack_t {
663 let thread_mem = unsafe { thread.as_ref().unwrap() };
664 let lock = unsafe { lock.as_ref().unwrap() };
665 let protected = thread_mem.protected.borrow(&lock.root);
666 *unsafe { protected.sigaltstack() }
667 }
668
669 #[unsafe(no_mangle)]
675 pub unsafe extern "C-unwind" fn shimshmem_setSigAltStack(
676 lock: *const ShimShmemHostLock,
677 thread: *const ShimShmemThread,
678 stack: linux_stack_t,
679 ) {
680 let thread_mem = unsafe { thread.as_ref().unwrap() };
681 let lock = unsafe { lock.as_ref().unwrap() };
682 let mut protected = thread_mem.protected.borrow_mut(&lock.root);
683 *unsafe { protected.sigaltstack_mut() } = stack;
684 }
685
686 #[unsafe(no_mangle)]
690 pub unsafe extern "C-unwind" fn shimshmem_incrementUnappliedCpuLatency(
691 lock: *mut ShimShmemHostLock,
692 dt: CSimulationTime,
693 ) {
694 let lock = unsafe { lock.as_mut().unwrap() };
695 lock.unapplied_cpu_latency += SimulationTime::from_c_simtime(dt).unwrap();
696 }
697
698 #[unsafe(no_mangle)]
702 pub unsafe extern "C-unwind" fn shimshmem_getUnappliedCpuLatency(
703 lock: *const ShimShmemHostLock,
704 ) -> CSimulationTime {
705 let lock = unsafe { lock.as_ref().unwrap() };
706 SimulationTime::to_c_simtime(Some(lock.unapplied_cpu_latency))
707 }
708
709 #[unsafe(no_mangle)]
713 pub unsafe extern "C-unwind" fn shimshmem_resetUnappliedCpuLatency(
714 lock: *mut ShimShmemHostLock,
715 ) {
716 let lock = unsafe { lock.as_mut().unwrap() };
717 lock.unapplied_cpu_latency = SimulationTime::ZERO;
718 }
719
720 #[unsafe(no_mangle)]
726 pub unsafe extern "C-unwind" fn shimshmem_getModelUnblockedSyscallLatency(
727 host: *const ShimShmemHost,
728 ) -> bool {
729 let host = unsafe { host.as_ref().unwrap() };
730 host.model_unblocked_syscall_latency
731 }
732
733 #[unsafe(no_mangle)]
740 pub unsafe extern "C-unwind" fn shimshmem_maxUnappliedCpuLatency(
741 host: *const ShimShmemHost,
742 ) -> CSimulationTime {
743 let host = unsafe { host.as_ref().unwrap() };
744 SimulationTime::to_c_simtime(Some(host.max_unapplied_cpu_latency))
745 }
746
747 #[unsafe(no_mangle)]
753 pub unsafe extern "C-unwind" fn shimshmem_unblockedSyscallLatency(
754 host: *const ShimShmemHost,
755 ) -> CSimulationTime {
756 let host = unsafe { host.as_ref().unwrap() };
757 SimulationTime::to_c_simtime(Some(host.unblocked_syscall_latency))
758 }
759
760 #[unsafe(no_mangle)]
766 pub unsafe extern "C-unwind" fn shimshmem_unblockedVdsoLatency(
767 host: *const ShimShmemHost,
768 ) -> CSimulationTime {
769 let host = unsafe { host.as_ref().unwrap() };
770 SimulationTime::to_c_simtime(Some(host.unblocked_vdso_latency))
771 }
772
773 #[unsafe(no_mangle)]
779 pub unsafe extern "C-unwind" fn shimshmem_getLoggingStartTime(
780 manager: *const ShimShmemManager,
781 ) -> i64 {
782 let manager = unsafe { manager.as_ref().unwrap() };
783 manager.log_start_time_micros
784 }
785
786 #[unsafe(no_mangle)]
792 pub unsafe extern "C-unwind" fn shimshmem_getEmulateCpuid(
793 manager: *const ShimShmemManager,
794 ) -> bool {
795 let manager = unsafe { manager.as_ref().unwrap() };
796 manager.emulate_cpuid
797 }
798}