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

Add basics for async wait support #33

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

MarkusBauer
Copy link

@MarkusBauer MarkusBauer commented Mar 1, 2025

Currently, we can only block while we wait for a child process to terminate, which limits in many cases.
A non-blocking version of wait() - named try_wait() allows users to implement more features, for example timeouts or async/await support.


For the reference: full async/await support could look like this snippet. This requires tokio as an additional dependency, thus I haven't added this code to the crate.

pub struct ChildWaiter<'a> {
    child: &'a mut Child,
    signal: tokio::signal::unix::Signal,
}

impl Future for ChildWaiter<'_> {
    type Output = io::Result<ExitStatus>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // mostly borrowed from tokio's command/process handling
        loop {
            let registered_interest = self.signal.poll_recv(cx).is_pending();

            if let Some(status) = self.child.try_wait()? {
                return Poll::Ready(Ok(status));
            }

            if registered_interest {
                return Poll::Pending;
            } else {
                continue;
            }
        }
    }
}

/// Get a future that completes when the process terminates
pub fn wait_async(child: &mut Child) -> ChildWaiter {
    ChildWaiter {
        child,
        signal: signal(SignalKind::child()).expect("failed to register signal handler"),
    }
}

Availability: If anyone wants to use this and other features before it's merged, check out my temporary fork. It includes #23 #27 #29 #33 #34 #35 and #36 with all conflicts resolved.
Add to your Cargo.toml: unshare = { git = "https://github.com/MarkusBauer/unshare.git" }

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

Successfully merging this pull request may close these issues.

1 participant