forked from tokio-rs/mio
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 tokio-rs#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 existing strong POSIX platforms like Linux can serve as a proxy to prove that the mio code is working nominally.
- Loading branch information
Showing
19 changed files
with
1,032 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
src/sys/unix/selector/adapters/edge_triggered/io_source_state.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use crate::{Interest, Registry, Token}; | ||
use std::io; | ||
use std::os::unix::io::RawFd; | ||
|
||
pub(crate) struct IoSourceState; | ||
|
||
impl IoSourceState { | ||
pub fn new() -> IoSourceState { | ||
IoSourceState | ||
} | ||
|
||
pub fn do_io<T, F, R>(&self, f: F, io: &T) -> io::Result<R> | ||
where | ||
F: FnOnce(&T) -> io::Result<R>, | ||
{ | ||
// We don't hold state, so we can just call the function and | ||
// return. | ||
f(io) | ||
} | ||
|
||
pub fn register( | ||
&mut self, | ||
registry: &Registry, | ||
token: Token, | ||
interests: Interest, | ||
fd: RawFd, | ||
) -> io::Result<()> { | ||
// Pass through, we don't have any state | ||
registry.selector().register(fd, token, interests) | ||
} | ||
|
||
pub fn reregister( | ||
&mut self, | ||
registry: &Registry, | ||
token: Token, | ||
interests: Interest, | ||
fd: RawFd, | ||
) -> io::Result<()> { | ||
// Pass through, we don't have any state | ||
registry.selector().reregister(fd, token, interests) | ||
} | ||
|
||
pub fn deregister(&mut self, registry: &Registry, fd: RawFd) -> io::Result<()> { | ||
// Pass through, we don't have any state | ||
registry.selector().deregister(fd) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
//! Implementation details for when we have an edge-triggered backend (i.e. epoll and kqueue). | ||
|
||
cfg_io_source! { | ||
pub(super) mod io_source_state; | ||
} | ||
|
||
pub(super) mod waker_registrar; |
19 changes: 19 additions & 0 deletions
19
src/sys/unix/selector/adapters/edge_triggered/waker_registrar.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use std::io; | ||
use std::os::fd::RawFd; | ||
use crate::{Interest, Token}; | ||
use crate::sys::Selector; | ||
|
||
#[derive(Debug)] | ||
pub(crate) struct WakerRegistrar; | ||
|
||
impl WakerRegistrar { | ||
pub fn register(selector: &Selector, fd: RawFd, token: Token) -> io::Result<Self> { | ||
selector.register(fd, token, Interest::READABLE)?; | ||
Ok(Self) | ||
} | ||
|
||
pub fn prepare_to_wake(&self) -> io::Result<()> { | ||
// Nothing to do in the case that we are using an edge-triggered API | ||
Ok(()) | ||
} | ||
} |
108 changes: 108 additions & 0 deletions
108
src/sys/unix/selector/adapters/level_triggered/io_source_state.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use crate::sys::Selector; | ||
use crate::{Interest, Registry, Token}; | ||
use std::io; | ||
use std::os::unix::io::RawFd; | ||
use std::sync::Arc; | ||
use crate::sys::unix::selector::poll::RegistrationRecord; | ||
|
||
struct InternalState { | ||
selector: Selector, | ||
token: Token, | ||
interests: Interest, | ||
fd: RawFd, | ||
shared_record: Arc<RegistrationRecord>, | ||
} | ||
|
||
impl Drop for InternalState { | ||
fn drop(&mut self) { | ||
if self.shared_record.is_registered() { | ||
let _ = self.selector.deregister(self.fd); | ||
} | ||
} | ||
} | ||
|
||
pub(crate) struct IoSourceState { | ||
inner: Option<Box<InternalState>>, | ||
} | ||
|
||
impl IoSourceState { | ||
pub fn new() -> IoSourceState { | ||
IoSourceState { inner: None } | ||
} | ||
|
||
pub fn do_io<T, F, R>(&self, f: F, io: &T) -> io::Result<R> | ||
where | ||
F: FnOnce(&T) -> io::Result<R>, | ||
{ | ||
let result = f(io); | ||
|
||
if let Err(err) = &result { | ||
println!("err={err:?}"); | ||
|
||
if err.kind() == io::ErrorKind::WouldBlock { | ||
self.inner.as_ref().map_or(Ok(()), |state| { | ||
state | ||
.selector | ||
.reregister(state.fd, state.token, state.interests) | ||
})?; | ||
} | ||
} | ||
|
||
result | ||
} | ||
|
||
pub fn register( | ||
&mut self, | ||
registry: &Registry, | ||
token: Token, | ||
interests: Interest, | ||
fd: RawFd, | ||
) -> io::Result<()> { | ||
if self.inner.is_some() { | ||
Err(io::ErrorKind::AlreadyExists.into()) | ||
} else { | ||
let selector = registry.selector().try_clone()?; | ||
|
||
selector.register_internal(fd, token, interests).map(move |shared_record| { | ||
let state = InternalState { | ||
selector, | ||
token, | ||
interests, | ||
fd, | ||
shared_record, | ||
}; | ||
|
||
self.inner = Some(Box::new(state)); | ||
}) | ||
} | ||
} | ||
|
||
pub fn reregister( | ||
&mut self, | ||
registry: &Registry, | ||
token: Token, | ||
interests: Interest, | ||
fd: RawFd, | ||
) -> io::Result<()> { | ||
match self.inner.as_mut() { | ||
Some(state) => registry | ||
.selector() | ||
.reregister(fd, token, interests) | ||
.map(|()| { | ||
state.token = token; | ||
state.interests = interests; | ||
}), | ||
None => Err(io::ErrorKind::NotFound.into()), | ||
} | ||
} | ||
|
||
pub fn deregister(&mut self, registry: &Registry, fd: RawFd) -> io::Result<()> { | ||
if let Some(state) = self.inner.take() { | ||
// Marking unregistered will short circuit the drop behaviour of calling | ||
// deregister so the call to deregister below is strictly required. | ||
state.shared_record.mark_unregistered(); | ||
} | ||
|
||
registry.selector().deregister(fd) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//! Implementation details for when we need to mimic an edge-triggered backend but actually have a | ||
//! level-triggered backend (e.g. poll). | ||
|
||
cfg_io_source! { | ||
pub(super) mod io_source_state; | ||
} | ||
|
||
pub(super) mod waker_registrar; |
Oops, something went wrong.