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

Use rustix instead of direct calls to libc. #76

Merged
merged 4 commits into from
Nov 30, 2022

Conversation

sunfishcode
Copy link
Contributor

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.

@notgull
Copy link
Member

notgull commented Jul 16, 2022

I support this in theory; async-io is only unsafe due to these lines of code. However, it looks like rustix is broken on Android. I'd support using nix, or even socket2 to make this cross platform.

@sunfishcode
Copy link
Contributor Author

Ah, this PR was using rustix 0.35.6-beta.2. The Android build error was fixed in the 0.35.6 release. I've now updated the PR.

@notgull
Copy link
Member

notgull commented Aug 17, 2022

Are there any blockers to this being merged? I see how the extra dependency might give pause, but it's probably worth purging the remaining unsafe code in this crate, at least on Unix.

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
Copy link
Member

@notgull notgull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Truth be told, this looks good to me.

With rustix in the dependency tree, it may be a good idea to also reimplement some other code in terms of rustix. For instance, the package has support for safe epoll, which means we may be able to reimplement our epoll backend in polling in terms of it to reduce the amount of unsafe code we use.

There are three main points of contention, from what I see:

  • Is there a reason to use this instead of nix? While rustix is more popular, nix may also appear in the dependency tree.
  • rustix adds the bitflags dependency to smol's dependency tree, which compiles fairly quickly but is still another brick in the wall.
  • Is the unsafe code we eliminate worth it in the end, since it's just replicated in rustix anyways?

@smol-rs/admins This may be worth a more thorough discussion to determine what direction we'd like to move in.

.read_with(|t| {
// Safety: Assume `as_raw_fd()` returns a valid fd; when `AsFd`
// is stabilized, we can remove this unsafe and simplify.
let fd = unsafe { BorrowedFd::borrow_raw(t.as_raw_fd()) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AsFd is stabilized now, so I think we can eliminate this unsafe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost, but async-io still has an MSRV of 1.48, and I/O safety is stabilized in Rust 1.63. I've now added more to these comments to mention that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't run the tests on the MSRV build, so it's alright.

@taiki-e
Copy link
Collaborator

taiki-e commented Nov 29, 2022

@sunfishcode

Thanks for the PR! I'm basically agreed with merging this, but have a few questions.

  • Are there tests for outline asm implementations for x86/arm/riscv? I could not find pre-1.59 tests in the rustix's CI files.
    (FWIW, if they are not tested, I think you can test those implementations with the latest rustc by inverting the asm cfg, like tokio does.)
  • Looking at the inline asm implementation of rustix, it seems that (in)lateout is used even where it seems unnecessary. At first glance, it looks fine, but you might want to make sure it is not affected by a bug like Incorrect handling of lateout pairs in inline asm rust-lang/rust#101346.
  • If we merge this, as notgull mentioned we also want to replace the direct dependencies on libc in other smol-rs crates (polling and async-process, IIRC) with rustix. I don't see a problem with async-process, but polling uses some platform-specific APIs such as bsd's kqueue, solarish's event ports, so probably can't switch to rustix right away except on linux.
    Is there any plan to support those non-linux platform-specific APIs in rustix? Or is patch to add support for them acceptable?

@notgull

  • Is there a reason to use this instead of nix? While rustix is more popular, nix may also appear in the dependency tree.

Given nix's MSRV policy (current MSRV is 1.56), it is difficult to have nix as a dependency of smol-rs crates.

  • Is the unsafe code we eliminate worth it in the end, since it's just replicated in rustix anyways?

Personally, I think the optimization such as uses of raw system calls to be the important benefit of this PR, not only the removal of unsafe code. (If the removal of unsafe code were the only benefit of this PR, I might not have agreed with this PR.)

Cargo.toml Outdated Show resolved Hide resolved
src/lib.rs Show resolved Hide resolved
@sunfishcode
Copy link
Contributor Author

* Are there tests for [_outline_](https://github.com/bytecodealliance/rustix/tree/main/src/backend/linux_raw/arch/outline) asm implementations for x86/arm/riscv? I could not find pre-1.59 tests in the `rustix`'s CI files.
  (FWIW, if they are not tested, I think you can test those implementations with the latest rustc by inverting the `asm` cfg, [like tokio does](https://github.com/tokio-rs/tokio/blob/28ec4a6161210a1ffb66cdcd7958b86b4b78b54e/tokio/build.rs#L97-L100).)

Ah, good catch. There are cargo check tests for 1.48, but not cargo test. And it looks like rustix has acquired some tests which are not compatible with Rust 1.48, so it's not trivial to just enable it. I'll look into fixing that.

Right now, I can confirm that with those tests commented out, the rest of the tests do still pass on 1.48 on all archtectures that have outline asm implementations.

* Looking at the inline asm implementation of `rustix`, it seems that `(in)lateout` is used even where it seems unnecessary. At first glance, it looks fine, but you might want to make sure it is not affected by a bug like [Incorrect handling of lateout pairs in inline asm rust-lang/rust#101346](https://github.com/rust-lang/rust/issues/101346).

Thanks for the heads-up here. Rustix doesn't have that specific pattern, with lateout with a virtual register, and has never seen a bug of this sort in any Rust version. But I'll also investigate this more.

* If we merge this, as notgull mentioned we also want to replace the direct dependencies on `libc` in other smol-rs crates ([`polling`](https://github.com/smol-rs/polling) and [`async-process`](https://github.com/smol-rs/async-process), IIRC) with `rustix`. I don't see a problem with `async-process`, but `polling` uses some platform-specific APIs such as bsd's kqueue, solarish's event ports, so probably can't switch to `rustix` right away except on linux.
  Is there any plan to support those non-linux platform-specific APIs in `rustix`? Or is patch to add support for them acceptable?

Rustix does have various non-Linux platform-specific APIs, for example fcopyfile. There's no specific plan; things get added as needed. Patches to add more are welcome. Filing issues is good too; polling APIs can be subtle, and I'd be happy to help figure things out.

Copy link
Collaborator

@taiki-e taiki-e left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@notgull notgull merged commit 8e1fa43 into smol-rs:master Nov 30, 2022
@notgull notgull mentioned this pull request Mar 21, 2023
notgull added a commit that referenced this pull request Mar 22, 2023
- Use [`rustix`] instead of [`libc`]/[`windows-sys`] for system calls (#76)
- Add a `will_fire` method to `Timer` to test if it will ever fire (#106)
- Reduce syscalls in `Async::new` (#107)
- Improve the drop ergonomics of `Readable` and `Writable` (#109)
- Change the "`wepoll`" in documentation to "`IOCP`" (#116)

[`rustix`]: https://crates.io/crates/rustix/
[`libc`]: https://crates.io/crates/libc/
[`windows-sys`]: https://crates.io/crates/windows-sys/
notgull added a commit that referenced this pull request Apr 28, 2023
- Use [`rustix`] instead of [`libc`]/[`windows-sys`] for system calls (#76)
- Add a `will_fire` method to `Timer` to test if it will ever fire (#106)
- Reduce syscalls in `Async::new` (#107)
- Improve the drop ergonomics of `Readable` and `Writable` (#109)
- Change the "`wepoll`" in documentation to "`IOCP`" (#116)

[`rustix`]: https://crates.io/crates/rustix/
[`libc`]: https://crates.io/crates/libc/
[`windows-sys`]: https://crates.io/crates/windows-sys/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants