//! Stage 19: mremap, by running `remaptest` (a musl static PIE): growing in //! place, shrinking, moving (MREMAP_MAYMOVE, MREMAP_FIXED), the errors, a //! file mapping, copy-on-write after a move in a forked child, and musl's //! realloc of big blocks. #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(rustbelt::test_runner)] #![reexport_test_harness_main = "test_main"] extern crate alloc; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; use bootloader::{BootInfo, entry_point}; use core::panic::PanicInfo; use rustbelt::fs::file::File; use rustbelt::process::{self, ExitStatus, SpawnArgs}; use rustbelt::{fs, memory, thread}; entry_point!(main); fn main(boot_info: &'static BootInfo) -> ! { rustbelt::init(); rustbelt::init_memory(boot_info); rustbelt::init_smp(); // moves must shoot down other CPUs' TLB entries fs::init(); rustbelt::init_storage(); test_main(); rustbelt::hlt_loop(); } /// Run /mnt/disk0/bin/`name` with `args`; its exit status and stdout. fn run(name: &str, args: &[&str]) -> (ExitStatus, String) { let (reader, writer) = fs::pipe::new(); let mut spawn = SpawnArgs::kernel(name); spawn.args.extend(args.iter().map(|a| String::from(*a))); spawn.stdio[1] = Arc::new(writer); let p = process::spawn_path(&alloc::format!("/mnt/disk0/bin/{}", name), spawn).expect("spawn failed"); let mut out = Vec::new(); let mut buf = [0u8; 256]; loop { match reader.read(&mut buf).unwrap() { 0 => break, n => out.extend_from_slice(&buf[..n]), } } (process::wait(&p), String::from_utf8_lossy(&out).into_owned()) } fn counts() -> (usize, usize, usize) { thread::sleep_ticks(3); (thread::thread_count(), process::count(), memory::frames_in_use()) } /// remaptest passes, twice, and the second run leaves nothing behind. #[test_case] fn remaptest_passes() { let (status, out) = run("remaptest", &[]); assert_eq!(status, ExitStatus::Exited(0), "output: {}", out); let before = counts(); let (status, out) = run("remaptest", &[]); assert_eq!(status, ExitStatus::Exited(0), "output: {}", out); assert!(out.contains("remaptest: all passed"), "output: {}", out); assert_eq!(counts(), before, "remaptest leaked something"); } /// `--trace` knows the name. #[test_case] fn trace_name() { assert_eq!(rustbelt::syscall::trace_name(25), "mremap"); } #[panic_handler] fn panic(info: &PanicInfo) -> ! { rustbelt::test_panic_handler(info) }