fix(wasi): enable all WasiFiles to be pollable (#3913)

Currently, the use of the downcast method means that you have to use one
of the hard-coded types. But Enarx needs to define its own `WasiFile`
implementations. This works fine, except the resulting files cannot be
used in poll because they aren't part of the hard-coded list.

Replace this with an accessor method for the pollable type in
`WasiFile`. Because we provide a default implementation of the method
and manually implement it on all the hard-coded types, this is backwards
compatible.

Signed-off-by: Nathaniel McCallum <nathaniel@profian.com>
This commit is contained in:
Nathaniel McCallum
2022-03-10 13:09:06 -05:00
committed by GitHub
parent 13b9396931
commit 0df4e961c0
10 changed files with 84 additions and 150 deletions

View File

@@ -1,15 +1,8 @@
use cap_std::time::Duration;
use io_lifetimes::{AsFd, BorrowedFd};
use rustix::io::{PollFd, PollFlags};
use std::convert::TryInto;
use wasi_common::{
file::WasiFile,
sched::{
subscription::{RwEventFlags, Subscription},
Poll,
},
Error, ErrorExt,
};
use wasi_common::sched::subscription::{RwEventFlags, Subscription};
use wasi_common::{sched::Poll, Error, ErrorExt};
pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> {
if poll.is_empty() {
@@ -19,16 +12,18 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> {
for s in poll.rw_subscriptions() {
match s {
Subscription::Read(f) => {
let fd = wasi_file_fd(f.file).ok_or(
Error::invalid_argument().context("read subscription fd downcast failed"),
)?;
let fd = f
.file
.pollable()
.ok_or(Error::invalid_argument().context("file is not pollable"))?;
pollfds.push(PollFd::from_borrowed_fd(fd, PollFlags::IN));
}
Subscription::Write(f) => {
let fd = wasi_file_fd(f.file).ok_or(
Error::invalid_argument().context("write subscription fd downcast failed"),
)?;
let fd = f
.file
.pollable()
.ok_or(Error::invalid_argument().context("file is not pollable"))?;
pollfds.push(PollFd::from_borrowed_fd(fd, PollFlags::OUT));
}
Subscription::MonotonicClock { .. } => unreachable!(),
@@ -85,30 +80,3 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> {
}
Ok(())
}
fn wasi_file_fd(f: &dyn WasiFile) -> Option<BorrowedFd<'_>> {
let a = f.as_any();
if a.is::<crate::file::File>() {
Some(a.downcast_ref::<crate::file::File>().unwrap().as_fd())
} else if a.is::<crate::net::TcpStream>() {
Some(a.downcast_ref::<crate::net::TcpStream>().unwrap().as_fd())
} else if a.is::<crate::net::TcpListener>() {
Some(a.downcast_ref::<crate::net::TcpListener>().unwrap().as_fd())
} else if a.is::<crate::net::UnixStream>() {
Some(a.downcast_ref::<crate::net::UnixStream>().unwrap().as_fd())
} else if a.is::<crate::net::UnixListener>() {
Some(
a.downcast_ref::<crate::net::UnixListener>()
.unwrap()
.as_fd(),
)
} else if a.is::<crate::stdio::Stdin>() {
Some(a.downcast_ref::<crate::stdio::Stdin>().unwrap().as_fd())
} else if a.is::<crate::stdio::Stdout>() {
Some(a.downcast_ref::<crate::stdio::Stdout>().unwrap().as_fd())
} else if a.is::<crate::stdio::Stderr>() {
Some(a.downcast_ref::<crate::stdio::Stderr>().unwrap().as_fd())
} else {
None
}
}