Skip to content

Commit d070937

Browse files
jastaThomasdezeeuw
authored andcommitted
Implement poll-based backend
Introduces a new backend for UNIX using the level triggered poll() syscall instead of epoll or kqueue. This support is crucial for embedded systems like the esp32 family but also for alternative operating systems like Haiku. This diff does not introduce any new platform support targets itself but provides the core technical implementation necessary to support these other targets. Future PRs will introduce specific platform support however due to reasons outlined in #1602 (many thanks for this initial effort BTW!) it is not possible to automate tests for those platforms. We will instead rely on the fact that Linux can serve as a proxy to prove that the mio code is working nominally. Note that only Linux has a sufficiently complex implementation to pass all tests. This is due to SIGRDHUP missing on other platforms and is required for about a dozen or so tests that check is_read_closed().
1 parent f20ec94 commit d070937

File tree

9 files changed

+984
-80
lines changed

9 files changed

+984
-80
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ jobs:
3131
run: cargo test --all-features
3232
- name: Tests release build
3333
run: cargo test --release --all-features
34+
TestPoll:
35+
runs-on: ubuntu-latest
36+
timeout-minutes: 10
37+
env:
38+
RUSTFLAGS="--cfg mio_unsupported_force_poll_poll"
39+
steps:
40+
- uses: actions/checkout@v3
41+
- uses: dtolnay/rust-toolchain@stable
42+
- name: Tests
43+
run: cargo test --all-features
44+
- name: Tests release build
45+
run: cargo test --release --all-features
3446
MinimalVersions:
3547
runs-on: ${{ matrix.os }}
3648
timeout-minutes: 10
@@ -133,6 +145,7 @@ jobs:
133145
runs-on: ubuntu-latest
134146
needs:
135147
- Test
148+
- TestPoll
136149
- MinimalVersions
137150
- MSRV
138151
- Nightly

src/io_source.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,7 @@ where
142142
) -> io::Result<()> {
143143
#[cfg(debug_assertions)]
144144
self.selector_id.associate(registry)?;
145-
registry
146-
.selector()
147-
.register(self.inner.as_raw_fd(), token, interests)
145+
self.state.register(registry, token, interests, self.inner.as_raw_fd())
148146
}
149147

150148
fn reregister(
@@ -155,15 +153,13 @@ where
155153
) -> io::Result<()> {
156154
#[cfg(debug_assertions)]
157155
self.selector_id.check_association(registry)?;
158-
registry
159-
.selector()
160-
.reregister(self.inner.as_raw_fd(), token, interests)
156+
self.state.reregister(registry, token, interests, self.inner.as_raw_fd())
161157
}
162158

163159
fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
164160
#[cfg(debug_assertions)]
165161
self.selector_id.remove_association(registry)?;
166-
registry.selector().deregister(self.inner.as_raw_fd())
162+
self.state.deregister(registry, self.inner.as_raw_fd())
167163
}
168164
}
169165

src/poll.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{event, sys, Events, Interest, Token};
2-
#[cfg(unix)]
2+
#[cfg(all(unix, not(mio_unsupported_force_poll_poll)))]
33
use std::os::unix::io::{AsRawFd, RawFd};
44
use std::time::Duration;
55
use std::{fmt, io};
@@ -411,7 +411,7 @@ impl Poll {
411411
}
412412
}
413413

414-
#[cfg(unix)]
414+
#[cfg(all(unix, not(mio_unsupported_force_poll_poll)))]
415415
impl AsRawFd for Poll {
416416
fn as_raw_fd(&self) -> RawFd {
417417
self.registry.as_raw_fd()
@@ -696,15 +696,18 @@ impl fmt::Debug for Registry {
696696
}
697697
}
698698

699-
#[cfg(unix)]
699+
#[cfg(all(unix, not(mio_unsupported_force_poll_poll)))]
700700
impl AsRawFd for Registry {
701701
fn as_raw_fd(&self) -> RawFd {
702702
self.selector.as_raw_fd()
703703
}
704704
}
705705

706706
cfg_os_poll! {
707-
#[cfg(unix)]
707+
#[cfg(all(
708+
unix,
709+
not(mio_unsupported_force_poll_poll)
710+
))]
708711
#[test]
709712
pub fn as_raw_fd() {
710713
let poll = Poll::new().unwrap();

src/sys/unix/mod.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,65 @@ cfg_os_poll! {
3333
}
3434

3535
cfg_io_source! {
36-
use std::io;
37-
3836
// Both `kqueue` and `epoll` don't need to hold any user space state.
39-
pub(crate) struct IoSourceState;
37+
#[cfg(not(mio_unsupported_force_poll_poll))]
38+
mod stateless_io_source {
39+
use std::io;
40+
use std::os::unix::io::RawFd;
41+
use crate::Registry;
42+
use crate::Token;
43+
use crate::Interest;
4044

41-
impl IoSourceState {
42-
pub fn new() -> IoSourceState {
43-
IoSourceState
44-
}
45+
pub(crate) struct IoSourceState;
46+
47+
impl IoSourceState {
48+
pub fn new() -> IoSourceState {
49+
IoSourceState
50+
}
51+
52+
pub fn do_io<T, F, R>(&self, f: F, io: &T) -> io::Result<R>
53+
where
54+
F: FnOnce(&T) -> io::Result<R>,
55+
{
56+
// We don't hold state, so we can just call the function and
57+
// return.
58+
f(io)
59+
}
4560

46-
pub fn do_io<T, F, R>(&self, f: F, io: &T) -> io::Result<R>
47-
where
48-
F: FnOnce(&T) -> io::Result<R>,
49-
{
50-
// We don't hold state, so we can just call the function and
51-
// return.
52-
f(io)
61+
pub fn register(
62+
&mut self,
63+
registry: &Registry,
64+
token: Token,
65+
interests: Interest,
66+
fd: RawFd,
67+
) -> io::Result<()> {
68+
// Pass through, we don't have any state
69+
registry.selector().register(fd, token, interests)
70+
}
71+
72+
pub fn reregister(
73+
&mut self,
74+
registry: &Registry,
75+
token: Token,
76+
interests: Interest,
77+
fd: RawFd,
78+
) -> io::Result<()> {
79+
// Pass through, we don't have any state
80+
registry.selector().reregister(fd, token, interests)
81+
}
82+
83+
pub fn deregister(&mut self, registry: &Registry, fd: RawFd) -> io::Result<()> {
84+
// Pass through, we don't have any state
85+
registry.selector().deregister(fd)
86+
}
5387
}
5488
}
89+
90+
#[cfg(not(mio_unsupported_force_poll_poll))]
91+
pub(crate) use self::stateless_io_source::IoSourceState;
92+
93+
#[cfg(mio_unsupported_force_poll_poll)]
94+
pub(crate) use self::selector::IoSourceState;
5595
}
5696

5797
cfg_os_ext! {

src/sys/unix/selector/mod.rs

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,58 @@
1-
#[cfg(any(
2-
target_os = "android",
3-
target_os = "illumos",
4-
target_os = "linux",
5-
target_os = "redox",
1+
#[cfg(all(
2+
not(mio_unsupported_force_poll_poll),
3+
any(
4+
target_os = "android",
5+
target_os = "illumos",
6+
target_os = "linux",
7+
target_os = "redox",
8+
)
69
))]
710
mod epoll;
811

9-
#[cfg(any(
10-
target_os = "android",
11-
target_os = "illumos",
12-
target_os = "linux",
13-
target_os = "redox",
12+
#[cfg(all(
13+
not(mio_unsupported_force_poll_poll),
14+
any(
15+
target_os = "android",
16+
target_os = "illumos",
17+
target_os = "linux",
18+
target_os = "redox",
19+
)
1420
))]
1521
pub(crate) use self::epoll::{event, Event, Events, Selector};
1622

17-
#[cfg(any(
18-
target_os = "dragonfly",
19-
target_os = "freebsd",
20-
target_os = "ios",
21-
target_os = "macos",
22-
target_os = "netbsd",
23-
target_os = "openbsd",
24-
target_os = "tvos",
25-
target_os = "watchos",
23+
#[cfg(mio_unsupported_force_poll_poll)]
24+
mod poll;
25+
26+
#[cfg(mio_unsupported_force_poll_poll)]
27+
pub(crate) use self::poll::{event, Event, Events, Selector, IoSourceState};
28+
29+
#[cfg(all(
30+
not(mio_unsupported_force_poll_poll),
31+
any(
32+
target_os = "dragonfly",
33+
target_os = "freebsd",
34+
target_os = "ios",
35+
target_os = "macos",
36+
target_os = "netbsd",
37+
target_os = "openbsd",
38+
target_os = "tvos",
39+
target_os = "watchos",
40+
)
2641
))]
2742
mod kqueue;
2843

29-
#[cfg(any(
30-
target_os = "dragonfly",
31-
target_os = "freebsd",
32-
target_os = "ios",
33-
target_os = "macos",
34-
target_os = "netbsd",
35-
target_os = "openbsd",
36-
target_os = "tvos",
37-
target_os = "watchos",
44+
#[cfg(all(
45+
not(mio_unsupported_force_poll_poll),
46+
any(
47+
target_os = "dragonfly",
48+
target_os = "freebsd",
49+
target_os = "ios",
50+
target_os = "macos",
51+
target_os = "netbsd",
52+
target_os = "openbsd",
53+
target_os = "tvos",
54+
target_os = "watchos",
55+
),
3856
))]
3957
pub(crate) use self::kqueue::{event, Event, Events, Selector};
4058

0 commit comments

Comments
 (0)