Skip to content

Commit 8e1fa43

Browse files
authored
Use rustix instead of direct calls to libc. (#76)
* Use rustix instead of direct calls to libc. Use the [rustix] syscall wrapper crate to factor out error handling and unsafe system calls. This reduces the amount of unsafe code here, and is a step towards factoring it out entirely once [`AsFd`] is stabilized and can replace `AsRawFd` for these kinds of uses. This does require incrementing the minimum required Rust version to 1.48. Please feel free to decline this PR if you don't wish to take on these new requirements. [rustix]: https://crates.io/crates/rustix/ [`AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html * Disable the use-libc-auxv feature. * Use rustix to call `FIONBIO` on Windows. This eliminates the need for a direct dependency on windows-sys. * Comment that we need Rust >= 1.63 to use io_safety.
1 parent 233b5ba commit 8e1fa43

File tree

4 files changed

+28
-30
lines changed

4 files changed

+28
-30
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ jobs:
9292
matrix:
9393
# When updating this, the reminder to update the minimum supported
9494
# Rust version in Cargo.toml.
95-
rust: ['1.46']
95+
rust: ['1.48']
9696
steps:
9797
- uses: actions/checkout@v3
9898
- name: Install Rust

Cargo.toml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ name = "async-io"
66
version = "1.12.0"
77
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
88
edition = "2018"
9-
rust-version = "1.46"
9+
rust-version = "1.48"
1010
description = "Async I/O and timers"
1111
license = "Apache-2.0 OR MIT"
1212
repository = "https://github.com/smol-rs/async-io"
@@ -25,19 +25,14 @@ futures-lite = "1.11.0"
2525
log = "0.4.11"
2626
parking = "2.0.0"
2727
polling = "2.0.0"
28+
rustix = { version = "0.36.0", default-features = false, features = ["std", "fs"] }
2829
slab = "0.4.2"
2930
socket2 = { version = "0.4.2", features = ["all"] }
3031
waker-fn = "1.1.0"
3132

3233
[build-dependencies]
3334
autocfg = "1"
3435

35-
[target."cfg(unix)".dependencies]
36-
libc = "0.2.77"
37-
38-
[target.'cfg(windows)'.dependencies]
39-
windows-sys = { version = "0.42", features = ["Win32_Networking_WinSock"] }
40-
4136
[dev-dependencies]
4237
async-channel = "1"
4338
async-net = "1"
@@ -49,7 +44,6 @@ tempfile = "3"
4944

5045
[target.'cfg(target_os = "linux")'.dev-dependencies]
5146
inotify = { version = "0.10", default-features = false }
52-
nix = { version = "0.25", default-features = false }
5347
timerfd = "1"
5448

5549
[target.'cfg(windows)'.dev-dependencies]

examples/linux-timerfd.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ fn main() -> std::io::Result<()> {
1414

1515
use async_io::Async;
1616
use futures_lite::future;
17+
use rustix::fd::BorrowedFd;
1718
use timerfd::{SetTimeFlags, TimerFd, TimerState};
1819

1920
/// Sleeps using an OS timer.
@@ -24,7 +25,14 @@ fn main() -> std::io::Result<()> {
2425

2526
// When the OS timer fires, a 64-bit integer can be read from it.
2627
Async::new(timer)?
27-
.read_with(|t| nix::unistd::read(t.as_raw_fd(), &mut [0u8; 8]).map_err(io::Error::from))
28+
.read_with(|t| {
29+
// Safety: We assume `as_raw_fd()` returns a valid fd. When we
30+
// can depend on Rust >= 1.63, where `AsFd` is stabilized, and
31+
// when `TimerFd` implements it, we can remove this unsafe and
32+
// simplify this.
33+
let fd = unsafe { BorrowedFd::borrow_raw(t.as_raw_fd()) };
34+
rustix::io::read(fd, &mut [0u8; 8]).map_err(io::Error::from)
35+
})
2836
.await?;
2937
Ok(())
3038
}

src/lib.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -598,21 +598,19 @@ impl<T: AsRawFd> Async<T> {
598598
/// # std::io::Result::Ok(()) });
599599
/// ```
600600
pub fn new(io: T) -> io::Result<Async<T>> {
601-
let fd = io.as_raw_fd();
601+
let raw = io.as_raw_fd();
602602

603603
// Put the file descriptor in non-blocking mode.
604-
unsafe {
605-
let mut res = libc::fcntl(fd, libc::F_GETFL);
606-
if res != -1 {
607-
res = libc::fcntl(fd, libc::F_SETFL, res | libc::O_NONBLOCK);
608-
}
609-
if res == -1 {
610-
return Err(io::Error::last_os_error());
611-
}
612-
}
604+
//
605+
// Safety: We assume `as_raw_fd()` returns a valid fd. When we can
606+
// depend on Rust >= 1.63, where `AsFd` is stabilized, and when
607+
// `TimerFd` implements it, we can remove this unsafe and simplify this.
608+
let fd = unsafe { rustix::fd::BorrowedFd::borrow_raw(raw) };
609+
let flags = rustix::fs::fcntl_getfl(fd)?;
610+
rustix::fs::fcntl_setfl(fd, flags | rustix::fs::OFlags::NONBLOCK)?;
613611

614612
Ok(Async {
615-
source: Reactor::get().insert_io(fd)?,
613+
source: Reactor::get().insert_io(raw)?,
616614
io: Some(io),
617615
})
618616
}
@@ -678,16 +676,14 @@ impl<T: AsRawSocket> Async<T> {
678676
/// ```
679677
pub fn new(io: T) -> io::Result<Async<T>> {
680678
let sock = io.as_raw_socket();
679+
let borrowed = unsafe { rustix::fd::BorrowedFd::borrow_raw(sock) };
681680

682681
// Put the socket in non-blocking mode.
683-
684-
use windows_sys::Win32::Networking::WinSock;
685-
686-
let mut nonblocking = true as _;
687-
let res = unsafe { WinSock::ioctlsocket(sock as _, WinSock::FIONBIO, &mut nonblocking) };
688-
if res != 0 {
689-
return Err(io::Error::last_os_error());
690-
}
682+
//
683+
// Safety: We assume `as_raw_socket()` returns a valid fd. When we can
684+
// depend on Rust >= 1.63, where `AsFd` is stabilized, and when
685+
// `TimerFd` implements it, we can remove this unsafe and simplify this.
686+
rustix::io::ioctl_fionbio(borrowed, true)?;
691687

692688
Ok(Async {
693689
source: Reactor::get().insert_io(sock)?,
@@ -1895,7 +1891,7 @@ fn connect(addr: SockAddr, domain: Domain, protocol: Option<Protocol>) -> io::Re
18951891
match socket.connect(&addr) {
18961892
Ok(_) => {}
18971893
#[cfg(unix)]
1898-
Err(err) if err.raw_os_error() == Some(libc::EINPROGRESS) => {}
1894+
Err(err) if err.raw_os_error() == Some(rustix::io::Errno::INPROGRESS.raw_os_error()) => {}
18991895
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
19001896
Err(err) => return Err(err),
19011897
}

0 commit comments

Comments
 (0)