diff --git a/Cargo.toml b/Cargo.toml index 46d90ab6..08c837af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -153,6 +153,7 @@ tempfile = "3" [profile.release] codegen-units = 1 panic = "abort" +debug = true [profile.dev] panic = "abort" diff --git a/src/hg_connect_stdio.rs b/src/hg_connect_stdio.rs index 4596995a..67f9c65f 100644 --- a/src/hg_connect_stdio.rs +++ b/src/hg_connect_stdio.rs @@ -341,7 +341,11 @@ pub fn get_stdio_connection(url: &Url, flags: c_int) -> Option> let mut writer = PrefixWriter::new("remote: ", stderr); let mut buf = [0; 1024]; 'outer: loop { - poll.poll(&mut events, None).unwrap(); + match poll.poll(&mut events, None) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::Interrupted => continue, + e => e.map(|_| ()).unwrap(), + } for event in &events { match event.token() { STDERR => { diff --git a/src/main.rs b/src/main.rs index 8496ee28..bb347701 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5182,6 +5182,7 @@ static mut HAS_GIT_REPO: bool = false; #[no_mangle] unsafe extern "C" fn cinnabar_main(_argc: c_int, argv: *const *const c_char) -> c_int { + hang_monitor(); let now = Instant::now(); // We look at argv[0] to choose what behavior to take, but it's not @@ -5235,6 +5236,7 @@ unsafe extern "C" fn cinnabar_main(_argc: c_int, argv: *const *const c_char) -> curl_sys::curl_global_cleanup(); } } + STOP.store(true, std::sync::atomic::Ordering::Relaxed); match ret { Ok(code) => code, Err(msg) => { @@ -5456,3 +5458,64 @@ pub fn experiment_similarity() -> &'static CStr { unsafe extern "C" fn do_panic(err: *const u8, len: usize) { panic!("{}", std::slice::from_raw_parts(err, len).as_bstr()); } + +use ::libc::{sigaction, syscall, SYS_tgkill}; + +static BACKTRACES: Mutex> = Mutex::new(Vec::new()); +static STOP: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); + +unsafe fn gettid() -> c_int { + syscall(::libc::SYS_gettid) as i32 +} + +extern "C" fn signal_handler(_sig: c_int) { + let bt = backtrace::Backtrace::new(); + let thread_id = unsafe { gettid() }; + let mut traces = BACKTRACES.lock().unwrap(); + traces.push((thread_id, format!("{:?}", bt))); +} + +fn hang_monitor() { + unsafe { + let mut sa: sigaction = std::mem::zeroed(); + sa.sa_sigaction = signal_handler as usize; + sa.sa_flags = ::libc::SA_SIGINFO; + sigaction(::libc::SIGUSR1, &sa, std::ptr::null_mut()); + } + std::thread::spawn(|| { + for _ in 0..10000 { + std::thread::sleep(std::time::Duration::from_millis(1)); + if STOP.load(std::sync::atomic::Ordering::Relaxed) { + return; + } + } + eprintln!("timeout"); + let self_tid = unsafe { gettid() }; + let tids = std::fs::read_dir("/proc/self/task") + .unwrap() + .map(|e| { + e.unwrap() + .file_name() + .into_string() + .unwrap() + .parse::() + .unwrap() + }) + .filter(|tid| *tid != self_tid) + .collect_vec(); + let ntids = tids.len(); + for tid in tids { + unsafe { + syscall(SYS_tgkill, ::libc::getpid(), tid, ::libc::SIGUSR1); + } + } + while BACKTRACES.lock().unwrap().len() < ntids { + std::thread::sleep(std::time::Duration::from_millis(1000)); + } + for (tid, bt) in &BACKTRACES.lock().unwrap()[..] { + eprintln!("Thread {}", tid); + eprintln!("{}", bt); + } + std::process::abort(); + }); +}