1 use std::env; 2 use std::panic; 3 use std::process::Command; 4 use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; 5 use std::sync::Arc; 6 use std::thread; 7 8 const PANICS: usize = 100; 9 const THREADS: usize = 8; 10 const VAR: &str = "__THE_TEST_YOU_ARE_LUKE"; 11 12 fn main() { 13 // These run in docker containers on CI where they can't re-exec the test, 14 // so just skip these for CI. No other reason this can't run on those 15 // platforms though. 16 // Miri does not have support for re-execing a file 17 if cfg!(unix) 18 && (cfg!(target_arch = "arm") 19 || cfg!(target_arch = "aarch64") 20 || cfg!(target_arch = "s390x")) 21 || cfg!(miri) 22 { 23 println!("test result: ok"); 24 return; 25 } 26 27 if env::var(VAR).is_err() { 28 parent(); 29 } else { 30 child(); 31 } 32 } 33 34 fn parent() { 35 let me = env::current_exe().unwrap(); 36 let result = Command::new(&me) 37 .env("RUST_BACKTRACE", "1") 38 .env(VAR, "1") 39 .output() 40 .unwrap(); 41 if result.status.success() { 42 println!("test result: ok"); 43 return; 44 } 45 println!("stdout:\n{}", String::from_utf8_lossy(&result.stdout)); 46 println!("stderr:\n{}", String::from_utf8_lossy(&result.stderr)); 47 println!("code: {}", result.status); 48 panic!(); 49 } 50 51 fn child() { 52 let done = Arc::new(AtomicBool::new(false)); 53 let done2 = done.clone(); 54 let a = thread::spawn(move || { 55 while !done2.load(SeqCst) { 56 format!("{:?}", backtrace::Backtrace::new()); 57 } 58 }); 59 60 let threads = (0..THREADS) 61 .map(|_| { 62 thread::spawn(|| { 63 for _ in 0..PANICS { 64 assert!(panic::catch_unwind(|| { 65 panic!(); 66 }) 67 .is_err()); 68 } 69 }) 70 }) 71 .collect::<Vec<_>>(); 72 for thread in threads { 73 thread.join().unwrap(); 74 } 75 76 done.store(true, SeqCst); 77 a.join().unwrap(); 78 } 79