nu_engine/
exit.rs

1use std::sync::atomic::Ordering;
2
3use nu_protocol::engine::EngineState;
4
5/// Exit the process or clean jobs if appropriate.
6///
7/// Drops `tag` and exits the current process if there are no running jobs, or if `exit_warning_given` is true.
8/// When running in an interactive session, warns the user if there
9/// were jobs and sets `exit_warning_given` instead, returning `tag` itself in that case.
10///
11// Currently, this `tag` argument exists mostly so that a LineEditor can be dropped before exiting the process.
12pub fn cleanup_exit<T>(tag: T, engine_state: &EngineState, exit_code: i32) -> T {
13    let mut jobs = engine_state.jobs.lock().expect("failed to lock job table");
14
15    if engine_state.is_interactive
16        && jobs.iter().next().is_some()
17        && !engine_state.exit_warning_given.load(Ordering::SeqCst)
18    {
19        let job_count = jobs.iter().count();
20
21        println!("There are still background jobs running ({}).", job_count);
22
23        println!("Running `exit` a second time will kill all of them.");
24
25        engine_state
26            .exit_warning_given
27            .store(true, Ordering::SeqCst);
28
29        return tag;
30    }
31
32    let _ = jobs.kill_all();
33
34    drop(tag);
35
36    std::process::exit(exit_code);
37}