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

Support VxWorks, Fuchsia and other Unix systems by using poll #26

Merged
merged 15 commits into from
Sep 11, 2021

Conversation

Kestrer
Copy link
Contributor

@Kestrer Kestrer commented Dec 17, 2020

Closes #20.

Notes:

  • I had to add the extra_traits feature to libc to #[derive(Debug)] on the polling implementation. This can be done manually to avoid activating the feature, if that's something you care about.
  • I had to #[derive(Clone, Copy)] on Event. It seems to be fine as Event's interface is already fully exposed.
  • I have tested this on Linux by disabling epoll and I have checked it compiles on Fuchsia (VxWorks and Haiku aren't supported by Rustup).

@ghost
Copy link

ghost commented Dec 17, 2020

Some quick questions before I do a deeper dive into the code...

Suppose a thread is blocked on wait(). Another thread then calls add() and the added FD is immediately ready.

  1. Is it ensured that wait() doesn't hold a mutex lock that blocks add() forever?
  2. Is it ensured that add() wakes up the caller of wait() even though the added FD is not in its poll set?

@Kestrer
Copy link
Contributor Author

Kestrer commented Dec 17, 2020

Thanks for pointing that out, I didn't consider those cases - I'll convert this to a draft.

@Kestrer Kestrer marked this pull request as draft December 17, 2020 20:29
@Kestrer Kestrer closed this Dec 18, 2020
@Kestrer Kestrer reopened this Dec 18, 2020
@Kestrer
Copy link
Contributor Author

Kestrer commented Dec 18, 2020

Ok, I think I've handled those cases now. Any call to add, modify or delete will interrupt the thread that's calling poll and send it into a condvar loop which it will exit if the user calls .notify() or all the operations complete.

@Kestrer Kestrer marked this pull request as ready for review December 18, 2020 17:56
src/poll.rs Outdated Show resolved Hide resolved
src/poll.rs Outdated
Comment on lines 50 to 59
/// The list of `pollfds` taken by poll.
///
/// The first file descriptor is always present and is used to notify the poller. It is also
/// stored in `notify_read`.
///
/// If the fd stored in here is `REMOVE_FD`, it should be removed.
poll_fds: Vec<libc::pollfd>,
/// The map of each file descriptor to data associated with it. This does not include the file
/// descriptors `notify_read` or `notify_write`.
fd_data: HashMap<RawFd, FdData>,
Copy link
Member

Choose a reason for hiding this comment

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

This seems to just implement an separately-ordered, hashmap. Why don't we pull in something like indexmap for this, or do we require some feature it doesn't have? (if true, which?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm averse to adding a dependency for this implementation, mostly because it would require a really long cfg in the Cargo.toml 😄. However, this comment did make me realize that I can make the implementation more efficient and simpler by using swap_remove instead of marking fds as removed and later removing them.

@fogti
Copy link
Member

fogti commented May 26, 2021

We use

[target."cfg(unix)".dependencies]
libc = { version = "0.2.77", features = ["extra_traits"] }

but

    } else if #[cfg(any(
        target_os = "vxworks",
        target_os = "fuchsia",
        unix,
    ))] {
        mod poll;
        use poll as sys;

and

// std::os::unix doesn't exist on Fuchsia
use libc::c_int as RawFd;

This is a mismatch between cfg-targets and should be fixed.
btw. if fixed, this would mean the justification in "I'm averse to adding a dependency for this implementation, mostly because it would require a really long cfg in the Cargo.toml" would no longer apply....

@Kestrer
Copy link
Contributor Author

Kestrer commented May 26, 2021

Ah right, the reason Fuchsia was compiling before is that it hasn't actually been changed to a target_family of None yet (it's still Unix). But now I've future-proofed it everywhere.

if fixed, this would mean the justification in "I'm averse to adding a dependency for this implementation, mostly because it would require a really long cfg in the Cargo.toml" would no longer apply....

It still applies, because the actual cfg required there would be cfg(any(target_os = "fuchsia", target_os = "vxworks", all(unix, not(any(target_os = "linux", target_os = "android", target_os = "illumos", target_os = "solaris", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly"))))).

@fogti
Copy link
Member

fogti commented May 26, 2021

Ah ok, didn't notice that libc is used in really many places...

@link2xt
Copy link

link2xt commented Jul 28, 2021

I have tested it on Haiku, works for me. Rustup indeed does not support Haiku, but rust can be installed with pkgman install rust_bin.

@taiki-e
Copy link
Collaborator

taiki-e commented Aug 3, 2021

I haven't reviewed this PR yet, but in mio, (IIUC) there was a discussion on poll's problems in the past: tokio-rs/mio#1472 (comment)
How does this PR deal with such problems?

@link2xt
Copy link

link2xt commented Aug 3, 2021

I haven't reviewed this PR yet, but in mio, (IIUC) there was a discussion on poll's problems in the past: tokio-rs/mio#1472 (comment)
How does this PR deal with such problems?

By storing all file descriptors inside a Poller, it's the first field of type Mutex<Fds>. Looks like polling does not have problems supporting poll.

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.

This looks good to me. Thanks for working on this!
(I'm not familiar with the platforms mentioned here, but I have tweaked this patch a bit and tested polling, async-io, and async-net on macOS.)

  • Could you update "supported platforms" docs on readme?

  • Could you add Fuchsia to cross workflow on CI? Probably something like:

    - name: Fuchsia
      if: startsWith(matrix.os, 'ubuntu')
      run: cross build --target x86_64-fuchsia

src/poll.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
@taiki-e
Copy link
Collaborator

taiki-e commented Aug 28, 2021

Also, would it be possible to add tests for the cases mentioned in #26 (comment) by Stjepan? I don't think tests for such a case currently exist.

Suppose a thread is blocked on wait(). Another thread then calls add() and the added FD is immediately ready.

  1. Is it ensured that wait() doesn't hold a mutex lock that blocks add() forever?
  2. Is it ensured that add() wakes up the caller of wait() even though the added FD is not in its poll set?

@Kestrer
Copy link
Contributor Author

Kestrer commented Sep 4, 2021

OK, I have done everything suggested 😊

Hopefully CI will pass...

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, Thanks @Kestrer!

@taiki-e taiki-e merged commit 4ac15ff into smol-rs:master Sep 11, 2021
@taiki-e
Copy link
Collaborator

taiki-e commented Nov 10, 2021

Published in v2.2.0.

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.

Add POSIX poll-based implementation
4 participants