Skip to content

Commit 8296d35

Browse files
committed
feat: add freebsd Waitable child
1 parent 07e9206 commit 8296d35

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exclude = ["/.*"]
1616

1717
[dependencies]
1818
async-lock = "3.0.0"
19-
async-io = "2.3.0"
19+
async-io = "2.4.0"
2020
cfg-if = "1.0"
2121
event-listener = "5.1.0"
2222
futures-lite = "2.0.0"
@@ -26,7 +26,7 @@ tracing = { version = "0.1.40", default-features = false, optional = true }
2626
async-signal = "0.2.3"
2727
rustix = { version = "1.0", default-features = false, features = ["std", "fs", "process"] }
2828

29-
[target.'cfg(any(windows, target_os = "linux"))'.dependencies]
29+
[target.'cfg(any(windows, target_os = "linux", target_os = "freebsd"))'.dependencies]
3030
async-channel = "2.0.0"
3131
async-task = "4.7.0"
3232

src/reaper/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
#![allow(irrefutable_let_patterns)]
1313

1414
/// Enable the waiting reaper.
15-
#[cfg(any(windows, target_os = "linux"))]
15+
#[cfg(any(windows, target_os = "linux", target_os = "freebsd"))]
1616
macro_rules! cfg_wait {
1717
($($tt:tt)*) => {$($tt)*};
1818
}
1919

2020
/// Enable the waiting reaper.
21-
#[cfg(not(any(windows, target_os = "linux")))]
21+
#[cfg(not(any(windows, target_os = "linux", target_os = "freebsd")))]
2222
macro_rules! cfg_wait {
2323
($($tt:tt)*) => {};
2424
}
@@ -48,7 +48,7 @@ use std::sync::Mutex;
4848

4949
/// The underlying system reaper.
5050
pub(crate) enum Reaper {
51-
#[cfg(any(windows, target_os = "linux"))]
51+
#[cfg(any(windows, target_os = "linux", target_os = "freebsd"))]
5252
/// The reaper based on the wait backend.
5353
Wait(wait::Reaper),
5454

@@ -59,7 +59,7 @@ pub(crate) enum Reaper {
5959

6060
/// The wrapper around a child.
6161
pub(crate) enum ChildGuard {
62-
#[cfg(any(windows, target_os = "linux"))]
62+
#[cfg(any(windows, target_os = "linux", target_os = "freebsd"))]
6363
/// The child guard based on the wait backend.
6464
Wait(wait::ChildGuard),
6565

@@ -70,7 +70,7 @@ pub(crate) enum ChildGuard {
7070

7171
/// A lock on the reaper.
7272
pub(crate) enum Lock {
73-
#[cfg(any(windows, target_os = "linux"))]
73+
#[cfg(any(windows, target_os = "linux", target_os = "freebsd"))]
7474
/// The wait-based reaper needs no lock.
7575
Wait,
7676

src/reaper/wait.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl ChildGuard {
134134
}
135135

136136
cfg_if::cfg_if! {
137-
if #[cfg(target_os = "linux")] {
137+
if #[cfg(any(target_os = "linux"))] {
138138
use async_io::Async;
139139
use rustix::process;
140140
use std::os::unix::io::OwnedFd;
@@ -219,9 +219,58 @@ cfg_if::cfg_if! {
219219
}
220220
}
221221

222+
/// Tell if we are able to use this backend.
223+
pub(crate) fn available() -> bool {
224+
true
225+
}
226+
} else if #[cfg(target_os = "freebsd")] {
227+
use async_io::os::kqueue::{Exit, Filter};
228+
use std::num::NonZeroI32;
229+
230+
/// Waitable version of `std::process::Child`
231+
struct WaitableChild {
232+
child: std::process::Child,
233+
handle: Filter<Exit>,
234+
}
235+
236+
impl WaitableChild {
237+
fn new(child: std::process::Child) -> io::Result<Self> {
238+
// std::process::Child id must provide a positive PID value
239+
let exit_filter = unsafe { Filter::new(Exit::from_pid(NonZeroI32::new_unchecked(
240+
child
241+
.id()
242+
.try_into()
243+
.expect("could not transform pid to i32 type")
244+
)))?
245+
};
246+
247+
248+
Ok(Self {
249+
handle: exit_filter,
250+
child: child,
251+
})
252+
}
253+
254+
fn get_mut(&mut self) -> &mut std::process::Child {
255+
&mut self.child
256+
}
257+
258+
fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<std::process::ExitStatus>> {
259+
loop {
260+
if let Some(status) = self.child.try_wait()? {
261+
return Poll::Ready(Ok(status));
262+
}
263+
264+
// Wait for us to become readable.
265+
futures_lite::ready!(self.handle.poll_ready(cx))?;
266+
}
267+
}
268+
}
269+
222270
/// Tell if we are able to use this backend.
223271
pub(crate) fn available() -> bool {
224272
true
225273
}
226274
}
275+
227276
}

0 commit comments

Comments
 (0)