Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for pid without polling using kevent on MacOS/BSD #1415

Open
Randomblock1 opened this issue Dec 6, 2024 · 5 comments
Open

Wait for pid without polling using kevent on MacOS/BSD #1415

Randomblock1 opened this issue Dec 6, 2024 · 5 comments

Comments

@Randomblock1
Copy link

On MacOS (and BSD), you can wait for a process to finish using kqueue/kevent (https://man.freebsd.org/cgi/man.cgi?query=kevent&manpath=FreeBSD+9.0-RELEASE) instead of polling waitpid. An old Apple technical note mentions this, which is how I originally found this. You can also get the exit status from the completed event this way.

Here's how I did it in my program (before realizing nix crate had event feature that let me not use unsafe):

use nix::libc;
let pid = 123;
unsafe {
    let mut kev = libc::kevent {
        ident: pid as usize,
        filter: libc::EVFILT_PROC,
        flags: libc::EV_ADD | libc::EV_ENABLE | libc::EV_ONESHOT | libc::EV_ERROR,
        fflags: libc::NOTE_EXITSTATUS,
        data: 0 as isize,
        udata: 0 as *mut std::os::raw::c_void,
    };
    libc::kevent(libc::kqueue(), &kev, 1, &mut kev, 1, std::ptr::null());
    if kev.flags & libc::EV_ERROR != 0 {
        if kev.data == libc::ESRCH as isize {
            println!("PID {} not found", pid);
        } else {
            eprintln!("kevent error waiting for PID {}", pid);
        }
        process::exit(1);
    }
    process::exit(kev.data as i32);
}

Probably not really needed since polling works fine but it'd be nice to have.

@GuillaumeGomez
Copy link
Owner

Code is more complex for a very small gain. Not sure it's worth it...

@Chaoses-Ib
Copy link
Contributor

On Windows one can also wait for a process by WaitForSingleObject and get its exit code by GetExitCodeProcess. Replacing polling may not have much benefit, but having exit code is useful. For example, one can monitor all processes and log their exit codes for debugging or auditing, or make a child process wait for its parent and log the code or restart it if it didn't exit normally.

@GuillaumeGomez
Copy link
Owner

I see. What would the API look like then?

@Chaoses-Ib
Copy link
Contributor

To avoid breaking change and make it obvious that some OS may not support this, I'd like to add a separate function, like

impl Process {
    /// ### Implementation notes
    /// Only Windows (and macOS) are supported.
    /// 
    /// On Windows, in addition to `PROCESS_QUERY_LIMITED_INFORMATION`, `PROCESS_QUERY_INFORMATION` access right is required.
    pub fn wait_with_status(&self) -> Option<ExitStatus> {
        todo!().map(std::process::ExitStatus::from_raw)
    }
}

@GuillaumeGomez
Copy link
Owner

Breaking change is fine considering there are already a few merged, so next release will be a major in any case. I also need to add a new System::kill_and_wait method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants