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

Redox OS support #844

Closed
wants to merge 41 commits into from
Closed

Redox OS support #844

wants to merge 41 commits into from

Conversation

jD91mZM2
Copy link

This was a part of my RSoC project of porting tokio and I think it's complete now :)

Tested:

  • Two small custom examples
  • 11/13 tokio examples work (udp servers might not be working but I'm getting 0.0.0.0:0 straight from rust which indicates this is a problem with either my setup or rust itself)
  • 6/7 hyper examples work (web_api is trying to connect to itself, which I think is generally broken - you can't even communicate between two netcat instances running on redox)

@jD91mZM2
Copy link
Author

Oof, seems like our net2 patch breaks windows support. Thank you AppVeyor :)

@jD91mZM2
Copy link
Author

Sometimes I really wish cargo would let you apply a patch to all dependencies

@jD91mZM2
Copy link
Author

We are currently trying to get net2 and other deps upstreamed. You might want to hold on to this PR until we're done :)

@carllerche
Copy link
Member

Thanks for doing this work.

Currently, adding additional platform support requires time from me that I do not have. I have written up an issue proposing how to address this here: #853. Thoughts?

To get this going, someone would have to step up to be the maintainer of Mio + Redox. Next, the PR would need to be updated to only impact redox. I noticed that dependencies Cargo.toml were updated, etc... these should be submitted as separate PRs. Also, all tests would need to pass.

@jD91mZM2
Copy link
Author

jD91mZM2 commented Jul 4, 2018

Initially I thought the version bumps were necessary to get miow to use the latest version of dependencies and therefore support redox. But Cargo is nice enough that 0.2.5 will also match 0.2.33 so a cargo update would suffice. I will separate it from this PR shortly.

Making the platform unstable for a while does not work very well with tokio since people would then indirectly use mio and can't control the features.

I guess I'll need to step up as maintainer for this.

@carllerche
Copy link
Member

We can continue the details of the process (stable vs. unstable) here: #853

@jD91mZM2
Copy link
Author

Bump?

Copy link
Collaborator

@Thomasdezeeuw Thomasdezeeuw left a comment

Choose a reason for hiding this comment

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

I've left a good number of small comments, mostly just small fixes. I have no idea if the code actually works, as I don't have Redox running. I think it would be nice if it could be tested on Travis.

Also I think the commits could be cleaned up.

Other then that this look good.

@@ -26,18 +26,21 @@ with-deprecated = []
default = ["with-deprecated"]

[dependencies]
lazycell = "1"
iovec = "0.1.2"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Some dependencies are downgraded, such lazycell and libc.

*/

pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
let (rd, wr) = try!(sys::pipe());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use sys::pipe()?. ? is prefered over try!.


pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
let (rd, wr) = try!(sys::pipe());
Ok((From::from(rd), From::from(wr)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can also use rd.into(), slightly smaller.


impl PipeReader {
pub fn from_stdout(stdout: process::ChildStdout) -> io::Result<Self> {
match sys::set_nonblock(stdout.as_raw_fd()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can use sys::set_nonblock(stdout.as_raw_fd())?.

Copy link
Author

Choose a reason for hiding this comment

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

Looks like most of this file was a copy paste of the unix code. Perhaps that should be cleaned up as well 😛

_ => {},
}
return Ok(PipeReader::from(unsafe { Io::from_raw_fd(stdout.into_raw_fd()) }));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add new empty line.

unsafe {
let bytes = (&self.efd).read(slice::from_raw_parts_mut(
evts.events.as_mut_ptr() as *mut u8,
evts.events.capacity() * mem::size_of::<syscall::Event>()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is incorrect. You're going beyond the bounds of the slice.

Copy link
Author

Choose a reason for hiding this comment

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

???

I'm taking the full vector, including the uninitialized contents, as a byte slice.
Then depending on how much the operating system read I set_len to update the vector's length.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm sorry, you're right. The code is fine I missed the fact that the type of the slice is changed to bytes.

pub struct Selector {
id: usize,
efd: File,
tokens: Mutex<BTreeMap<RawFd, BTreeSet<Token>>>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not use HashMap and HashSet? Just curious.

Copy link
Author

Choose a reason for hiding this comment

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

No idea, I just went with what Jeremy did. I heard someone mention you for some reason couldn't use HashMaps inside the redox kernel, so perhaps he just got used to BTrees...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, well then it's fine to leave it.

}

pub fn try_clone(&self) -> io::Result<TcpStream> {
self.inner.try_clone().map(|s| {
Copy link
Collaborator

Choose a reason for hiding this comment

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

self.inner.try_clone().map(TcpStream::from_stream)?

}
}

impl<'a> Read for &'a TcpStream {
Copy link
Collaborator

Choose a reason for hiding this comment

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

As with other Read/Write implementations on references; this is ok to do in Redox?


pub fn set_only_v6(&self, _only_v6: bool) -> io::Result<()> {
//self.io.set_only_v6(only_v6)
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe unimplemented!()? Since I would like to know this while developing, but I'm not sure about this.

Copy link
Author

@jD91mZM2 jD91mZM2 Jul 23, 2018

Choose a reason for hiding this comment

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

The idea is that an application can fall back to something else

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok. So I would be correct to assum it's not implemented in Redox?

@jD91mZM2
Copy link
Author

jD91mZM2 commented Jul 23, 2018

Thank you for taking a look!

While fixing the things I noticed unix now has a uds module??? Since when are unix sockets a thing? I'll have to port that as well I guess. (Oh, it's deprecated.)

Anyway, if you want the commits squashed you're welcome to do so. I'd prefer that the pull request itself keeps the history

@jD91mZM2
Copy link
Author

Could you restart the appveyor test? I really doubt I affected that 😛

}
}

impl<'a> Read for &'a PipeReader {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, then this looks good to me.


impl From<Io> for PipeReader {
fn from(io: Io) -> PipeReader {
PipeReader { io: io }
Copy link
Collaborator

Choose a reason for hiding this comment

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

PipeReader { io } works here.


impl From<Io> for PipeWriter {
fn from(io: Io) -> PipeWriter {
PipeWriter { io: io }
Copy link
Collaborator

Choose a reason for hiding this comment

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

PipeWriter { io }

src/net/tcp.rs Outdated
@@ -7,12 +7,16 @@
//!
/// [portability guidelines]: ../struct.Poll.html#portability

#[cfg(windows)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Your right I was look at TcpStream::connect, but it uses SocketAddr::V4.


#[derive(Debug)]
pub struct Selector {
id: usize,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, nevermind then.

pub fn select(&self, evts: &mut Events, awakener: Token, timeout: Option<Duration>) -> io::Result<bool> {
let mut timeout_fd = None;
if let Some(timeout) = timeout {
let mut file = File::open(format!("time:{}", CLOCK_MONOTONIC))?;
Copy link
Collaborator

@Thomasdezeeuw Thomasdezeeuw Jul 23, 2018

Choose a reason for hiding this comment

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

Didn't know about File::open allocating. Then lets leave this for a future pr.

@Thomasdezeeuw
Copy link
Collaborator

A lot of things are resolved, good job. But is there a way to test this in CI? That would really ensure that the code keeps working in the future as well.

@jD91mZM2
Copy link
Author

I'd love to add CI support, but the policy for adding new platforms has not yet been completely resolved, and @asomers' suggested changes would imply that redox starts off without a CI until it gets a lower tier.

@carllerche
Copy link
Member

At the very least, it would be nice if there was some sort of cross compilation test to ensure that it compiled at the very least.

@carllerche
Copy link
Member

@hawkw could you review this? I would not focus on any of the implementation details. The only thing of import is that no existing code is impacted short of mod declarations & use statements that are scoped with a cfg for redox.

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

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

@carllerche I've commented on a few changes in this branch that seem unrelated to adding Redox support.

inner: s,
}
})
self.inner.try_clone().map(Self::from_stream)
Copy link
Member

Choose a reason for hiding this comment

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

This change seems unrelated from the rest of this branch?

src/net/tcp.rs Outdated
if cfg!(windows) {
sock.bind(&inaddr_any(addr))?;
}
#[cfg(windows)]
Copy link
Member

Choose a reason for hiding this comment

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

The change from if cfg!(windows) { ... } to #[cfg(windows)] is probably better, but seems unrelated to adding Redox support.

src/net/tcp.rs Outdated
@@ -389,6 +401,7 @@ impl TcpStream {
}
}

#[cfg(windows)]
Copy link
Member

Choose a reason for hiding this comment

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

Again, this seems unrelated to Redox support.

src/net/tcp.rs Outdated
if cfg!(unix) {
sock.reuse_address(true)?;
}
#[cfg(unix)]
Copy link
Member

Choose a reason for hiding this comment

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

Change from if cfg!(...) to #[cfg(...)] attribute seems unrelated.

src/net/tcp.rs Outdated
@@ -7,12 +7,16 @@
//!
/// [portability guidelines]: ../struct.Poll.html#portability

#[cfg(windows)]
Copy link
Member

Choose a reason for hiding this comment

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

Looks like an unrelated change?

[target.'cfg(unix)'.dependencies]
libc = "0.2.42"
libc = "0.2.42"
Copy link
Member

Choose a reason for hiding this comment

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

Unrelated formatting change (though, this did need to be fixed, I think).

lazycell = "1"
log = "0.4"
net2 = "0.2.33"
Copy link
Member

Choose a reason for hiding this comment

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

Were the dependency version bumps necessary for adding Redox support?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, net2 only recently has redox support

Copy link
Member

Choose a reason for hiding this comment

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

Okay, thanks for clearing that up!

@jD91mZM2
Copy link
Author

@carllerche Didn't want to set up a CI until I got thumbs up, especially with @asomers' proposed platform policy (which would only allow a CI at tier 2). With your permission I shall do so now.

@jD91mZM2 jD91mZM2 force-pushed the master branch 2 times, most recently from 31a1372 to 0a4b663 Compare August 18, 2018 10:00
@jD91mZM2
Copy link
Author

Guessing the current CI issue is unrelated?

@hawkw
Copy link
Member

hawkw commented Aug 18, 2018

@jD91mZM2, yeah, the iOS CI job is busted (#863). I have a PR open (#865) to fix it which should hopefully be merged soon.

BTW, thanks for backing out the unrelated changes for now. I think several of them (such as using #[cfg(...)] rather than if cfg!(...)) would probably be good to have in the long run, but those changes probably ought to land in their own branch.

Copy link
Member

@carllerche carllerche left a comment

Choose a reason for hiding this comment

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

Thanks, I added some inline comments. I think we can get this to a point where it can be merged soon.

src/lib.rs Outdated
@@ -198,12 +201,13 @@ pub use poll::Iter as EventsIter;
#[doc(hidden)]
pub use io::deprecated::would_block;

#[cfg(all(unix, not(target_os = "fuchsia")))]
#[cfg(any(all(unix, not(target_os = "fuchsia")), target_os = "redox"))]
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to move this to a separate block? So, split out the cfg(redox) and have a separate pub mod unix? It would make it easier to manage IMO.

src/net/tcp.rs Outdated
@@ -7,12 +7,16 @@
//!
/// [portability guidelines]: ../struct.Poll.html#portability

#[cfg(not(target_os = "redox"))]
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain on why this file needs changes?

I would prefer to avoid adding platform cfg guards in src/net/tcp.

Copy link
Author

Choose a reason for hiding this comment

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

Back when I wrote this, I would argue that "redox doesn't support creating non-blocking sockets before an address is bound". I am extremely certain that I tried it, but... I've seen the source code of redox' libc now, and it seems to disagree.

It's still always better to use native rust where possible (redox' backend doesn't use libc), but I cannot safely say the old code won't wory. I'll try it again, later.

Copy link
Author

@jD91mZM2 jD91mZM2 Aug 21, 2018

Choose a reason for hiding this comment

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

Just double checked, also checked the code. There are unbound sockets implemented, but they don't support fcntl. I'll ask in the community chat what they'd like to do here.

@@ -683,24 +709,24 @@ impl fmt::Debug for TcpListener {
*
*/

#[cfg(all(unix, not(target_os = "fuchsia")))]
#[cfg(any(all(unix, not(target_os = "fuchsia")), target_os = "redox"))]
Copy link
Member

Choose a reason for hiding this comment

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

I'm wondering if these impls should be moved out of this file in order to maintain the goal of "no cfgs" in this file.

Copy link
Author

Choose a reason for hiding this comment

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

Is that a question or an order? Personally I think it makes sense to keep them here since they're all identical content-wise (apart from fuschia), it's just a bummer redox doesn't count as unix for some reason

@jD91mZM2
Copy link
Author

jD91mZM2 commented Aug 21, 2018

The latest changes separate stuff into their respective platforms. This obviously also affects unix/windows, but not more than strictly necessary. I might be able to revert and keep redox consistent to unix if the redox netstack team gives me thumbs up to implement fcntl for unbound sockets

@carllerche
Copy link
Member

Ok, here is the plan. Lets get this in the 0.7 release of Mio.

I commented with a proposed implementation strategy for adding new platforms here. This proposal is based on how this PR needs to touch so many files. I want to avoid this.

So, if my proposed strategy is accepted, the contents of sys/redox would be moved into a dedicated crate that mio would conditionally depend on (repoll?). Also, we would split out the cfg flags... I'll probably work on some of this restructuring on master.

wdyt?

@jD91mZM2
Copy link
Author

I appreciate the idea, it sounds pretty great! I'm afraid, however, I might just drop this PR in its entirety as rust-lang/rust#60139 is merging. Redox is moving its focus away from updating the world to rely directly on Redox APIs, and instead making the C API cover everything. So I am sorry if I made you figure out this policy for smaller gain than expected, but I hope you can still use it for the other platforms as it sounds like a great idea in general.

@jD91mZM2 jD91mZM2 closed this May 10, 2019
@carllerche
Copy link
Member

Sorry about all that. The policy is still going to be valuable I think.

However, even w/ redox targettng unix, I would guess that some level of redox specific integration is going to be needed. There are linux, bsd, etc... specific code for implementing the selector.

@jD91mZM2
Copy link
Author

jD91mZM2 commented May 11, 2019

That's true, someone will probably open a small PR to add redox to the linux cfgs, soon enough. We seem to be going the epoll route in our C standard library relibc. 😄

@Thomasdezeeuw
Copy link
Collaborator

@jD91mZM2 this is likely not the place for it, but I would recommend kqueue over epoll. The API in my opinion is much easier to use and supports I/O, signals, timers and use space events all with 2 system calls.

@jD91mZM2
Copy link
Author

jD91mZM2 commented May 11, 2019

@Thomasdezeeuw I will look up kqueue and hear with the BDFL if he thinks implementing it instead (or alongside?) of his epoll implementation is worth it. Thanks a lot!

EDIT: This will require kernel support to be any better than a compatibility layer around epoll.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants