run_shell 0.1.13

shell script written in rust
Documentation
use errno::Errno;
use libc;
use libc::c_int;
use libc::sigset_t;
use local_shell::LocalShell;
use result::check_errno;
use result::ShellError;
use std::collections::HashMap;
use std::mem::MaybeUninit;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::thread::ThreadId;

/// Managing global child process state.
pub struct ProcessManager {
    children: HashMap<ThreadId, Arc<Mutex<LocalShell>>>,
}

impl ProcessManager {
    fn new() -> ProcessManager {
        ProcessManager {
            children: HashMap::new(),
        }
    }

    pub fn add_local_shell(&mut self, id: &ThreadId, shell: &Arc<Mutex<LocalShell>>) {
        self.children.insert(id.clone(), shell.clone());
    }

    pub fn remove_local_shell(&mut self, id: &ThreadId) {
        self.children.remove(id);
    }
}

/// Traps SIGINT and SIGTERM, waits for child process completion, and exits
/// the current process.
///
/// It must be invoked before any thread is launched, because it internally
/// uses pthread_sigmask.
#[allow(warnings)]
pub fn trap_signal_and_wait_children() -> Result<(), ShellError> {
    unsafe {
        let mut sigset = MaybeUninit::<sigset_t>::uninit();
        check_errno("sigemptyset", libc::sigemptyset(&mut sigset.assume_init()))?;
        check_errno(
            "sigaddset",
            libc::sigaddset(&mut sigset.assume_init(), libc::SIGINT),
        )?;
        check_errno(
            "sigaddset",
            libc::sigaddset(&mut sigset.assume_init(), libc::SIGTERM),
        )?;

        let mut oldset = MaybeUninit::<sigset_t>::uninit();
        let result = libc::pthread_sigmask(
            libc::SIG_BLOCK,
            &mut sigset.assume_init(),
            &mut oldset.assume_init(),
        );
        if result != 0 {
            return Err(ShellError::Errno("pthread_sigmask", Errno(result)));
        }

        thread::spawn(move || {
            info!("Start waitinig signal");
            let mut signal: c_int = 0;
            let result = libc::sigwait(&sigset.assume_init(), &mut signal as *mut c_int);
            if result != 0 {
                eprintln!("sigwait failed {}", result);
                return;
            }
            info!("Signal {} is received", signal);
            let mut lock = PROCESS_MANAGER.lock().unwrap();
            let mut children = lock.children.drain().collect::<Vec<_>>();
            info!("Wait for {} child processes exiting", children.len());
            for &mut (_, ref entry) in &mut children {
                let mut lock = entry.lock().unwrap();
                lock.wait();
            }
            ::std::process::exit(128 + signal);
        });
        Ok(())
    }
}

lazy_static! {
    pub static ref PROCESS_MANAGER: Mutex<ProcessManager> = Mutex::new(ProcessManager::new());
}