From 8ec1b096cd919907a688d3d7dfcce9052cd1be5e Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Fri, 5 Apr 2024 10:13:14 +0200 Subject: [PATCH 1/3] For #152 - Remove signal-hook dependency --- Cargo.lock | 20 -------------------- Cargo.toml | 3 +-- src/interrupt.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/ps.rs | 49 ++++++++++++++++++------------------------------ 5 files changed, 69 insertions(+), 53 deletions(-) create mode 100644 src/interrupt.rs diff --git a/Cargo.lock b/Cargo.lock index ba99a63..2b56725 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,31 +8,11 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - [[package]] name = "sonar" version = "0.10.0" dependencies = [ "libc", - "signal-hook", "subprocess", ] diff --git a/Cargo.toml b/Cargo.toml index b7a73f8..3bfdd69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -subprocess = "0.2" libc = "0.2" -signal-hook = { version = "0.3", default-features = false, features = [] } +subprocess = "0.2" diff --git a/src/interrupt.rs b/src/interrupt.rs new file mode 100644 index 0000000..c400d84 --- /dev/null +++ b/src/interrupt.rs @@ -0,0 +1,49 @@ +use std::sync::atomic::{AtomicBool, Ordering}; + +// Signal handling logic. +// +// Assuming no bugs, the interesting interrupt signals are SIGHUP, SIGTERM, SIGINT, and SIGQUIT. Of +// these, only SIGHUP and SIGTERM are really interesting because they are sent by the OS or by job +// control (and will often be followed by SIGKILL if not honored within some reasonable time); +// INT/QUIT are sent by a user in response to keyboard action and more typical during +// development/debugging. +// +// Call handle_interruptions() to establish handlers, then is_interrupted() to check whether signals +// have been received. + +static INTERRUPTED: AtomicBool = AtomicBool::new(false); + +extern "C" fn sonar_signal_handler(_: libc::c_int) { + INTERRUPTED.store(true, Ordering::Relaxed); +} + +pub fn handle_interruptions() { + unsafe { + let nomask : libc::sigset_t = std::mem::zeroed(); + let mut action = libc::sigaction { + sa_sigaction: sonar_signal_handler as usize, + sa_mask: nomask, + sa_flags: 0, + sa_restorer: None, + }; + libc::sigaction(libc::SIGTERM, &mut action, std::ptr::null_mut()); + libc::sigaction(libc::SIGHUP, &mut action, std::ptr::null_mut()); + } +} + +#[cfg(debug_assertions)] +pub fn is_interrupted() -> bool { + if std::env::var("SONARTEST_WAIT_INTERRUPT").is_ok() { + std::thread::sleep(std::time::Duration::new(10, 0)); + } + let flag = INTERRUPTED.load(Ordering::Relaxed); + if flag { + println!("Interrupt flag was set!") + } + flag +} + +#[cfg(not(debug_assertions))] +pub fn is_interrupted() -> bool { + INTERRUPTED.load(Ordering::Relaxed) +} diff --git a/src/main.rs b/src/main.rs index 5172b92..2388261 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod batchless; mod command; mod gpu; mod hostname; +mod interrupt; mod jobs; mod log; mod nvidia; diff --git a/src/ps.rs b/src/ps.rs index 99967e5..6e8a7fa 100644 --- a/src/ps.rs +++ b/src/ps.rs @@ -3,6 +3,7 @@ use crate::amd; use crate::hostname; +use crate::interrupt; use crate::jobs; use crate::log; use crate::nvidia; @@ -11,13 +12,8 @@ use crate::procfsapi; use crate::util::{csv_quote,three_places}; use std::collections::{HashMap, HashSet}; -use std::env; use std::io::{self, Result, Write}; use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::thread; -use std::time; // The GpuSet has three states: // @@ -177,26 +173,17 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest // perform the operation. // // However if a signal arrives in the middle of the operation and terminates the program the - // lock file may be left on disk. Assuming no bugs, the interesting signals are SIGHUP, - // SIGTERM, SIGINT, and SIGQUIT. Of these, only SIGHUP and SIGTERM are really interesting - // because they are sent by the OS or by job control (and will often be followed by SIGKILL if - // not honored within some reasonable time); INT/QUIT are sent by a user in response to keyboard - // action and more typical during development/debugging. + // lock file may be left on disk. Therefore some lightweight signal handling is desirable to + // trap signals and clean up orderly. // - // So THE MAIN REASON TO HANDLE SIGNALS is to make sure we're not killed while we hold the lock - // file, during normal operation. To do that, we just need to ignore the signal. + // Additionally, if a signal is detected, we do not wish to start new operations, we can just + // skip them. Code therefore calls is_interrupted() at strategic points to check whether a + // signal was detected. // - // But if a handled signal is received, it would be sensible to exit as quickly as possible and - // with minimal risk of hanging. And to do that, we record the signal and then check the flag - // often, and we avoid starting things if the flag is set, and we produce no output (if - // possible) once the flag becomes set, yet produce complete output if any output at all. - // - // There's no reason to limit the signal handler to the case when we have a lock file, the same - // logic can apply to both paths. + // Finally, there's no reason to limit the signal handler to the case when we have a lock file, + // the same logic can apply to both paths. - let interrupted = Arc::new(AtomicBool::new(false)); - signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&interrupted)).unwrap(); - signal_hook::flag::register(signal_hook::consts::SIGHUP, Arc::clone(&interrupted)).unwrap(); + interrupt::handle_interruptions(); if let Some(ref dirname) = opts.lockdir { let mut created = false; @@ -208,7 +195,7 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest p.push(dirname); p.push("sonar-lock.".to_string() + &hostname); - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -237,13 +224,14 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest } if !failed && !skip { - do_create_snapshot(jobs, opts, timestamp, &interrupted); + do_create_snapshot(jobs, opts, timestamp); // Testing code: If we got the lockfile and produced a report, wait 10s after producing // it while holding onto the lockfile. It is then possible to run sonar in that window // while the lockfile is being held, to ensure the second process exits immediately. + #[cfg(debug_assertions)] if std::env::var("SONARTEST_WAIT_LOCKFILE").is_ok() { - thread::sleep(time::Duration::new(10, 0)); + std::thread::sleep(std::time::Duration::new(10, 0)); } } @@ -263,7 +251,7 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest log::error("Unable to properly manage or delete lockfile"); } } else { - do_create_snapshot(jobs, opts, timestamp, &interrupted); + do_create_snapshot(jobs, opts, timestamp); } } @@ -271,12 +259,11 @@ fn do_create_snapshot( jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timestamp: &str, - interrupted: &Arc, ) { let no_gpus = empty_gpuset(); let mut proc_by_pid = ProcTable::new(); - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -331,7 +318,7 @@ fn do_create_snapshot( ); // gpu_mem_size_kib } - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -371,7 +358,7 @@ fn do_create_snapshot( } } - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -416,7 +403,7 @@ fn do_create_snapshot( } } - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } From d44ebdae2f9ef787d3b944c0b9f6b2d48e9552aa Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Fri, 5 Apr 2024 10:16:59 +0200 Subject: [PATCH 2/3] Undo --- Cargo.lock | 20 ++++++++++++++++++++ Cargo.toml | 3 ++- src/interrupt.rs | 49 ------------------------------------------------ src/main.rs | 1 - src/ps.rs | 49 ++++++++++++++++++++++++++++++------------------ 5 files changed, 53 insertions(+), 69 deletions(-) delete mode 100644 src/interrupt.rs diff --git a/Cargo.lock b/Cargo.lock index 2b56725..ba99a63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,11 +8,31 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "sonar" version = "0.10.0" dependencies = [ "libc", + "signal-hook", "subprocess", ] diff --git a/Cargo.toml b/Cargo.toml index 3bfdd69..b7a73f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = "0.2" subprocess = "0.2" +libc = "0.2" +signal-hook = { version = "0.3", default-features = false, features = [] } diff --git a/src/interrupt.rs b/src/interrupt.rs deleted file mode 100644 index c400d84..0000000 --- a/src/interrupt.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering}; - -// Signal handling logic. -// -// Assuming no bugs, the interesting interrupt signals are SIGHUP, SIGTERM, SIGINT, and SIGQUIT. Of -// these, only SIGHUP and SIGTERM are really interesting because they are sent by the OS or by job -// control (and will often be followed by SIGKILL if not honored within some reasonable time); -// INT/QUIT are sent by a user in response to keyboard action and more typical during -// development/debugging. -// -// Call handle_interruptions() to establish handlers, then is_interrupted() to check whether signals -// have been received. - -static INTERRUPTED: AtomicBool = AtomicBool::new(false); - -extern "C" fn sonar_signal_handler(_: libc::c_int) { - INTERRUPTED.store(true, Ordering::Relaxed); -} - -pub fn handle_interruptions() { - unsafe { - let nomask : libc::sigset_t = std::mem::zeroed(); - let mut action = libc::sigaction { - sa_sigaction: sonar_signal_handler as usize, - sa_mask: nomask, - sa_flags: 0, - sa_restorer: None, - }; - libc::sigaction(libc::SIGTERM, &mut action, std::ptr::null_mut()); - libc::sigaction(libc::SIGHUP, &mut action, std::ptr::null_mut()); - } -} - -#[cfg(debug_assertions)] -pub fn is_interrupted() -> bool { - if std::env::var("SONARTEST_WAIT_INTERRUPT").is_ok() { - std::thread::sleep(std::time::Duration::new(10, 0)); - } - let flag = INTERRUPTED.load(Ordering::Relaxed); - if flag { - println!("Interrupt flag was set!") - } - flag -} - -#[cfg(not(debug_assertions))] -pub fn is_interrupted() -> bool { - INTERRUPTED.load(Ordering::Relaxed) -} diff --git a/src/main.rs b/src/main.rs index 2388261..5172b92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ mod batchless; mod command; mod gpu; mod hostname; -mod interrupt; mod jobs; mod log; mod nvidia; diff --git a/src/ps.rs b/src/ps.rs index 6e8a7fa..99967e5 100644 --- a/src/ps.rs +++ b/src/ps.rs @@ -3,7 +3,6 @@ use crate::amd; use crate::hostname; -use crate::interrupt; use crate::jobs; use crate::log; use crate::nvidia; @@ -12,8 +11,13 @@ use crate::procfsapi; use crate::util::{csv_quote,three_places}; use std::collections::{HashMap, HashSet}; +use std::env; use std::io::{self, Result, Write}; use std::path::PathBuf; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::thread; +use std::time; // The GpuSet has three states: // @@ -173,17 +177,26 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest // perform the operation. // // However if a signal arrives in the middle of the operation and terminates the program the - // lock file may be left on disk. Therefore some lightweight signal handling is desirable to - // trap signals and clean up orderly. + // lock file may be left on disk. Assuming no bugs, the interesting signals are SIGHUP, + // SIGTERM, SIGINT, and SIGQUIT. Of these, only SIGHUP and SIGTERM are really interesting + // because they are sent by the OS or by job control (and will often be followed by SIGKILL if + // not honored within some reasonable time); INT/QUIT are sent by a user in response to keyboard + // action and more typical during development/debugging. // - // Additionally, if a signal is detected, we do not wish to start new operations, we can just - // skip them. Code therefore calls is_interrupted() at strategic points to check whether a - // signal was detected. + // So THE MAIN REASON TO HANDLE SIGNALS is to make sure we're not killed while we hold the lock + // file, during normal operation. To do that, we just need to ignore the signal. // - // Finally, there's no reason to limit the signal handler to the case when we have a lock file, - // the same logic can apply to both paths. + // But if a handled signal is received, it would be sensible to exit as quickly as possible and + // with minimal risk of hanging. And to do that, we record the signal and then check the flag + // often, and we avoid starting things if the flag is set, and we produce no output (if + // possible) once the flag becomes set, yet produce complete output if any output at all. + // + // There's no reason to limit the signal handler to the case when we have a lock file, the same + // logic can apply to both paths. - interrupt::handle_interruptions(); + let interrupted = Arc::new(AtomicBool::new(false)); + signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&interrupted)).unwrap(); + signal_hook::flag::register(signal_hook::consts::SIGHUP, Arc::clone(&interrupted)).unwrap(); if let Some(ref dirname) = opts.lockdir { let mut created = false; @@ -195,7 +208,7 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest p.push(dirname); p.push("sonar-lock.".to_string() + &hostname); - if interrupt::is_interrupted() { + if interrupted.load(Ordering::Relaxed) { return; } @@ -224,14 +237,13 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest } if !failed && !skip { - do_create_snapshot(jobs, opts, timestamp); + do_create_snapshot(jobs, opts, timestamp, &interrupted); // Testing code: If we got the lockfile and produced a report, wait 10s after producing // it while holding onto the lockfile. It is then possible to run sonar in that window // while the lockfile is being held, to ensure the second process exits immediately. - #[cfg(debug_assertions)] if std::env::var("SONARTEST_WAIT_LOCKFILE").is_ok() { - std::thread::sleep(std::time::Duration::new(10, 0)); + thread::sleep(time::Duration::new(10, 0)); } } @@ -251,7 +263,7 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest log::error("Unable to properly manage or delete lockfile"); } } else { - do_create_snapshot(jobs, opts, timestamp); + do_create_snapshot(jobs, opts, timestamp, &interrupted); } } @@ -259,11 +271,12 @@ fn do_create_snapshot( jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timestamp: &str, + interrupted: &Arc, ) { let no_gpus = empty_gpuset(); let mut proc_by_pid = ProcTable::new(); - if interrupt::is_interrupted() { + if interrupted.load(Ordering::Relaxed) { return; } @@ -318,7 +331,7 @@ fn do_create_snapshot( ); // gpu_mem_size_kib } - if interrupt::is_interrupted() { + if interrupted.load(Ordering::Relaxed) { return; } @@ -358,7 +371,7 @@ fn do_create_snapshot( } } - if interrupt::is_interrupted() { + if interrupted.load(Ordering::Relaxed) { return; } @@ -403,7 +416,7 @@ fn do_create_snapshot( } } - if interrupt::is_interrupted() { + if interrupted.load(Ordering::Relaxed) { return; } From 22fbe82c5908030c58602a2bbb2ddf23947303e0 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Fri, 5 Apr 2024 10:17:54 +0200 Subject: [PATCH 3/3] For #152 - Remove signal-hook dependency --- Cargo.lock | 20 -------------------- Cargo.toml | 3 +-- src/interrupt.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/ps.rs | 49 ++++++++++++++++++------------------------------ 5 files changed, 69 insertions(+), 53 deletions(-) create mode 100644 src/interrupt.rs diff --git a/Cargo.lock b/Cargo.lock index ba99a63..2b56725 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,31 +8,11 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - [[package]] name = "sonar" version = "0.10.0" dependencies = [ "libc", - "signal-hook", "subprocess", ] diff --git a/Cargo.toml b/Cargo.toml index b7a73f8..3bfdd69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -subprocess = "0.2" libc = "0.2" -signal-hook = { version = "0.3", default-features = false, features = [] } +subprocess = "0.2" diff --git a/src/interrupt.rs b/src/interrupt.rs new file mode 100644 index 0000000..c400d84 --- /dev/null +++ b/src/interrupt.rs @@ -0,0 +1,49 @@ +use std::sync::atomic::{AtomicBool, Ordering}; + +// Signal handling logic. +// +// Assuming no bugs, the interesting interrupt signals are SIGHUP, SIGTERM, SIGINT, and SIGQUIT. Of +// these, only SIGHUP and SIGTERM are really interesting because they are sent by the OS or by job +// control (and will often be followed by SIGKILL if not honored within some reasonable time); +// INT/QUIT are sent by a user in response to keyboard action and more typical during +// development/debugging. +// +// Call handle_interruptions() to establish handlers, then is_interrupted() to check whether signals +// have been received. + +static INTERRUPTED: AtomicBool = AtomicBool::new(false); + +extern "C" fn sonar_signal_handler(_: libc::c_int) { + INTERRUPTED.store(true, Ordering::Relaxed); +} + +pub fn handle_interruptions() { + unsafe { + let nomask : libc::sigset_t = std::mem::zeroed(); + let mut action = libc::sigaction { + sa_sigaction: sonar_signal_handler as usize, + sa_mask: nomask, + sa_flags: 0, + sa_restorer: None, + }; + libc::sigaction(libc::SIGTERM, &mut action, std::ptr::null_mut()); + libc::sigaction(libc::SIGHUP, &mut action, std::ptr::null_mut()); + } +} + +#[cfg(debug_assertions)] +pub fn is_interrupted() -> bool { + if std::env::var("SONARTEST_WAIT_INTERRUPT").is_ok() { + std::thread::sleep(std::time::Duration::new(10, 0)); + } + let flag = INTERRUPTED.load(Ordering::Relaxed); + if flag { + println!("Interrupt flag was set!") + } + flag +} + +#[cfg(not(debug_assertions))] +pub fn is_interrupted() -> bool { + INTERRUPTED.load(Ordering::Relaxed) +} diff --git a/src/main.rs b/src/main.rs index 5172b92..2388261 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod batchless; mod command; mod gpu; mod hostname; +mod interrupt; mod jobs; mod log; mod nvidia; diff --git a/src/ps.rs b/src/ps.rs index 99967e5..6e8a7fa 100644 --- a/src/ps.rs +++ b/src/ps.rs @@ -3,6 +3,7 @@ use crate::amd; use crate::hostname; +use crate::interrupt; use crate::jobs; use crate::log; use crate::nvidia; @@ -11,13 +12,8 @@ use crate::procfsapi; use crate::util::{csv_quote,three_places}; use std::collections::{HashMap, HashSet}; -use std::env; use std::io::{self, Result, Write}; use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::thread; -use std::time; // The GpuSet has three states: // @@ -177,26 +173,17 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest // perform the operation. // // However if a signal arrives in the middle of the operation and terminates the program the - // lock file may be left on disk. Assuming no bugs, the interesting signals are SIGHUP, - // SIGTERM, SIGINT, and SIGQUIT. Of these, only SIGHUP and SIGTERM are really interesting - // because they are sent by the OS or by job control (and will often be followed by SIGKILL if - // not honored within some reasonable time); INT/QUIT are sent by a user in response to keyboard - // action and more typical during development/debugging. + // lock file may be left on disk. Therefore some lightweight signal handling is desirable to + // trap signals and clean up orderly. // - // So THE MAIN REASON TO HANDLE SIGNALS is to make sure we're not killed while we hold the lock - // file, during normal operation. To do that, we just need to ignore the signal. + // Additionally, if a signal is detected, we do not wish to start new operations, we can just + // skip them. Code therefore calls is_interrupted() at strategic points to check whether a + // signal was detected. // - // But if a handled signal is received, it would be sensible to exit as quickly as possible and - // with minimal risk of hanging. And to do that, we record the signal and then check the flag - // often, and we avoid starting things if the flag is set, and we produce no output (if - // possible) once the flag becomes set, yet produce complete output if any output at all. - // - // There's no reason to limit the signal handler to the case when we have a lock file, the same - // logic can apply to both paths. + // Finally, there's no reason to limit the signal handler to the case when we have a lock file, + // the same logic can apply to both paths. - let interrupted = Arc::new(AtomicBool::new(false)); - signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&interrupted)).unwrap(); - signal_hook::flag::register(signal_hook::consts::SIGHUP, Arc::clone(&interrupted)).unwrap(); + interrupt::handle_interruptions(); if let Some(ref dirname) = opts.lockdir { let mut created = false; @@ -208,7 +195,7 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest p.push(dirname); p.push("sonar-lock.".to_string() + &hostname); - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -237,13 +224,14 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest } if !failed && !skip { - do_create_snapshot(jobs, opts, timestamp, &interrupted); + do_create_snapshot(jobs, opts, timestamp); // Testing code: If we got the lockfile and produced a report, wait 10s after producing // it while holding onto the lockfile. It is then possible to run sonar in that window // while the lockfile is being held, to ensure the second process exits immediately. + #[cfg(debug_assertions)] if std::env::var("SONARTEST_WAIT_LOCKFILE").is_ok() { - thread::sleep(time::Duration::new(10, 0)); + std::thread::sleep(std::time::Duration::new(10, 0)); } } @@ -263,7 +251,7 @@ pub fn create_snapshot(jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timest log::error("Unable to properly manage or delete lockfile"); } } else { - do_create_snapshot(jobs, opts, timestamp, &interrupted); + do_create_snapshot(jobs, opts, timestamp); } } @@ -271,12 +259,11 @@ fn do_create_snapshot( jobs: &mut dyn jobs::JobManager, opts: &PsOptions, timestamp: &str, - interrupted: &Arc, ) { let no_gpus = empty_gpuset(); let mut proc_by_pid = ProcTable::new(); - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -331,7 +318,7 @@ fn do_create_snapshot( ); // gpu_mem_size_kib } - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -371,7 +358,7 @@ fn do_create_snapshot( } } - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; } @@ -416,7 +403,7 @@ fn do_create_snapshot( } } - if interrupted.load(Ordering::Relaxed) { + if interrupt::is_interrupted() { return; }