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 Freebsd #102

Merged
merged 6 commits into from
Oct 25, 2016
Merged

Support Freebsd #102

merged 6 commits into from
Oct 25, 2016

Conversation

dlrobertson
Copy link
Contributor

Add support for FreeBSD and rename linux module to unix.

NB: Some tests are still currently failing on freebsd. I believe most of which have to do with system limits e.g. (platform::medium_data blocks on a send_followup_fragment due to system limits and never recovers).

Copy link
Contributor Author

@dlrobertson dlrobertson left a comment

Choose a reason for hiding this comment

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

Some brief comments on things changed.

@@ -26,18 +26,64 @@ use std::thread;

const MAX_FDS_IN_CMSG: u32 = 64;

const SCM_RIGHTS: c_int = 0x01;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved static and const delarations to the top

fn CMSG_ALIGN(length: size_t) -> size_t {
(length + mem::size_of::<size_t>() - 1) & !(mem::size_of::<size_t>() - 1)
#[cfg(target_os = "freebsd")]
unsafe fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void {
Copy link
Contributor Author

@dlrobertson dlrobertson Sep 18, 2016

Choose a reason for hiding this comment

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

Ensure proper alignment. cmsg.offset(1) on my box is the equivalent of addq 0xc, %rcx, but it should be addq 0x10, %rcx.

(*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
(*cmsg_buffer).cmsg_type = SCM_RIGHTS;

ptr::copy_nonoverlapping(fds.as_ptr(),
cmsg_buffer.offset(1) as *mut c_int,
CMSG_DATA(cmsg_buffer) as *mut c_int,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use CMSG_DATA instead of ptr::offset

@antrik
Copy link
Contributor

antrik commented Sep 18, 2016

@danlrobertson I'm not sure if/when I get to look at the changes in detail; so some quick comments for now:

  1. Formalities: I believe the changes you commented on here should actually be separate commits, with the comments as commit messages. The comments here won't be terribly useful when someone tries to make sense of the Git changelog at some point in the future...
  2. The CMSG_DATA/CMSG_ALIGN/CMSG_LEN macros are direct copies of macros from Linux-specific bits of glibc, only translated to Rust -- so they obviously need system-specific variants. The code invoking them on the other hand should be portable I think...
  3. This might be considered out of scope -- but I have been thinking for a while that these extremely system-specific details should probably not be present in the code of ipc-channel at all, but rather covered by external crates, such as nix and/or libc -- though quite probably this will require some upstream enhancements to said crates...

@dlrobertson
Copy link
Contributor Author

@antrik thanks for the quick reply. Don't feel rushed.

  1. Shouldn't be a problem.

  2. The changes I made to the FreeBSD specific CMSG_DATA function was also a translation of the C macro. I don't see how the current code can be written to be more portable without something along the lines of 3.

  3. I completely agree. I was surprised this wasn't in libc

@l0kod
Copy link

l0kod commented Sep 19, 2016

About the CMSG_DATA, you may be interested in https://github.com/stemjail/fdpass-rs

@dlrobertson
Copy link
Contributor Author

dlrobertson commented Sep 19, 2016

@antrik: Updated to include 2 commits. fbafaf1 move static and const declarations and 6e68729 support freebsd

@l0kod: per stemjail/fdpass-rs#1, it doesn't seem to be currently working on FreeBSD. Let me know if missed something. A transition to a library like fdpass-rs I think is a great idea (and the path forward), but imo that is currently outside the scope of this PR. That being said, I'm happy to look into it further if the consensus is to do so.

@antrik
Copy link
Contributor

antrik commented Sep 20, 2016

@l0kod I briefly considered fdpass-rs when I first read about it; but it seems to me nix with its much broader scope would be more appropriate for ipc-channel...

Copy link
Contributor

@antrik antrik left a comment

Choose a reason for hiding this comment

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

Personally, I'd prefer even finer-grained commits, with changes such as "rename platform/linux to platform/unix", "introduce (and use) CMSG_DATA()", "factor out new_sockaddr_un()", "use socklen_t", "create sockaddr in a platform-agnostic fashion" etc. all as separate patches... But then again, I'm a confirmed perfectionist, so my standards probably shouldn't be considered normative ;-)

@@ -26,18 +26,64 @@ use std::thread;

const MAX_FDS_IN_CMSG: u32 = 64;

const SCM_RIGHTS: c_int = 0x01;
Copy link
Contributor

@antrik antrik Sep 26, 2016

Choose a reason for hiding this comment

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

To be honest, I'm not convinced moving these defines to the top really is an improvement... Personally I prefer definitions to be close to usage, rather than strictly following formal rules such as "all const should go to the top". But I'm aware that I might be in a minority here :-(

(Also, this is a bit off-topic I guess, but I'm still wondering why this one is not defined in libc?...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It apears as if everything from cmsg is not defined in libc. It definitely seems like they should be defined somewhere like libc or nix.

Copy link
Contributor

Choose a reason for hiding this comment

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

libc I'd say. libc is for the raw FFI interfaces; while nix is for safe wrappers around them. Using nix to abstract all these dirty details would be nice to have, but it's a second (much bigger) step...

// The value Linux returns for SO_SNDBUF
// is not the size we are actually allowed to use...
// Empirically, we have to deduct 32 bytes from that.
const RESERVED_SIZE: usize = 32;
Copy link
Contributor

@antrik antrik Sep 26, 2016

Choose a reason for hiding this comment

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

Have you checked that this is actually needed on FreeBSD as well? It's the kind of thing I would have expected to be extremely system-specific...

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 want to say yes, but I'll double check.

#[cfg(target_os="linux")]
type IovLen = usize;
#[cfg(target_os="linux")]
type SockLen = usize;
Copy link
Contributor

@antrik antrik Sep 26, 2016

Choose a reason for hiding this comment

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

Can't we just use socklen_t everywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's what I was hoping. However, socklen_t:linux = u32 but msghdr.msg_controllen = size_t = usize. This works on FreeBSD though, and was what I originally did. Perhaps this is another change that should be made to libc

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, so for some reason the POSIX committee decided to abuse socklen_t for something that is clearly not in any way related to socket address lengths; while glibc decided to stick with the more appropriate size_t... This is so retarded :-(

Calling the type SockLen is very confusing though, as it has no bearing on the primary use of socklen_t -- better call it MsgControllen, or something along these lines. Also, it's probably better to define it as size_t rather than usize, to match the libc definition.

#[cfg(target_os="linux")]
type SockLen = usize;
#[cfg(target_os="linux")]
#[inline]
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd leave that decision to the compiler...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

let mut sockaddr = sockaddr_un {
sun_family: libc::AF_UNIX as u16,
sun_path: [ 0; 108 ],
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect we could make this code generic, by using mem::zeroed() and then setting only the fields we need, just as we would in C? (Along with using sa_family_t to make the cast generic -- though I wonder why AF_UNIX isn't defined as sa_family_t in libc in the first place...)

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'll give it a shot.

libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
path,
sockaddr.sun_path.len() - 1);
let len = mem::size_of::<sockaddr_un>() - 104 + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
Copy link
Contributor

@antrik antrik Sep 26, 2016

Choose a reason for hiding this comment

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

This doesn't look right -- copy&paste error perhaps?...

I think we could make that code (and thus the entire function) generic as well. It will be uglier than in C due to the lack of offsetof; but it should be doable with &sockaddr.sun_path as *const as usize - &sockaddr as *const as usize or something along these lines?...

BTW, the example in the Linux man page for using AF_UNIX sockets just passes sizeof sockaddr_un as the len parameter to connect(), rather than calculating the actual size in use... The POSIX man page for connect() is a bit unclear what is expected here: it says "the length of the sockaddr structure pointed to by the address argument". I'd tend to assume passing the entire size is probably correct... Which will make the code simpler.

(I suggest changing this in a separate commit before the main change.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this is an error. linux would be - 108, while freebsd would be - 104

@@ -953,21 +976,32 @@ fn is_socket(fd: c_int) -> bool {

// FFI stuff follows:

const SCM_RIGHTS: c_int = 0x01;
#[allow(non_snake_case)]
fn CMSG_LEN(length: SockLen) -> SockLen {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it's right for these functions to work on SockLen: I'd say they should stick with size_t; while the cast to socklen_t would only be done by the caller while filling the actual socket structures. This feels more natural to me, and avoids a lot of unnecessary confusing casts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed 👍

CMSG_ALIGN(mem::size_of::<cmsghdr>()) + length
#[cfg(target_os = "linux")]
unsafe fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void {
cmsg.offset(1) as *mut c_void
Copy link
Contributor

Choose a reason for hiding this comment

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

While this matches the glibc definition of CMSG_DATA, I think it wouldn't hurt to just use FreeBSD definition everywhere? AIUI, Linux only gets away with the simplistic definition, because sizeof cmsghdr happens to always have the right alignment there. This is inconsistent with the other CMSG_ definitions though, which are defined in a more generic way, always explicitly doing the alignment...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Didn't think about that. That would make this a bit more simplistic. I'd definitely be okay with making this change

@@ -0,0 +1,1029 @@
// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
Copy link
Contributor

Choose a reason for hiding this comment

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

Something went wrong with your commit: it introduces both src/platform/unix/mod.rs and src/platform/unix/linux/mod.rs (with identical contents) in place of the original src/platform/linux/mod.rs...

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'll fix this in the update... My bad.

@dlrobertson
Copy link
Contributor Author

Thanks for the very thorough review. I'll make the changes and comment when I make the update. I'll also start looking into a better home for cmsg

Move the static and const declarations to the top of the file
@dlrobertson
Copy link
Contributor Author

Personally, I'd prefer even finer-grained commits

Updated, and I must admit you were right... It makes a lot more sense this way.

Calling the type SockLen is very confusing though.. better call it MsgControllen

Updated.

Also, it's probably better to define it as size_t rather than usize, to match the libc definition.

Updated.

I suspect we could make this code [new_sockaddr_un] generic, by using mem::zeroed() and then setting only the fields we need

Updated.

#[cfg(all(not(feature = "force-inprocess"), target_os = "linux"))]
include!("linux/mod.rs");
#[cfg(all(not(feature = "force-inprocess"), any(target_os = "linux",
target_os = "freebsd")))]
Copy link
Contributor

@antrik antrik Oct 5, 2016

Choose a reason for hiding this comment

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

Personally, I'd add the freebsd case only right before or along with actually adding FreeBSD-specific code, after the generic portability improvements... But this way is fine too I guess :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what you mean by this. Do you mean use something like a all(unix,not(macos)) instead of specifying linux and freebsd for using the unix module?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, I was only referring to how changes are split up into patches, rather than the final code. (Sorry for being so pedantic about this... It's really not important; just a suggestion :-) )

Having said that, I already pondered something along the lines of what you said here. I'm honestly not sure. Normally, I'd prefer this approach indeed; but in this specific case, we need to handle each platform explicitly anyway because of the MsgControllen ugliness :-( It might still be a win though -- especially if this can be handled at the libc level at some point?...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated with the suggested patch splits.

Agreed. In the future we could/should be able to get away with just unix.

unsafe fn new_sockaddr_un(path: *const c_char) -> (sockaddr_un, usize) {
let mut sockaddr: sockaddr_un = mem::zeroed();
libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
path, sockaddr.sun_path.len() - 1);
sockaddr.sun_family = libc::AF_UNIX as u16;
sockaddr.sun_family = libc::AF_UNIX as SunFamily;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't you just use sa_family_t here as I suggested?...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup. Good point.

@@ -961,7 +954,7 @@ fn CMSG_LEN(length: size_t) -> size_t {
}

#[allow(non_snake_case)]
fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void {
unsafe fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that belongs with the previous commit?...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My bad

let mut sockaddr: sockaddr_un = mem::zeroed();
libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
path, sockaddr.sun_path.len() - 1);
sockaddr.sun_family = libc::AF_UNIX as u16;
Copy link
Contributor

@antrik antrik Oct 5, 2016

Choose a reason for hiding this comment

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

I'd split the commits a bit differently: first only split out new_sockaddr_un(), without any change to the actual code moved in there, so it's a pure refactoring; and only after that one or more commits that actually make it platform-agnostic, by introducing mem::zeroed(), sa_family_t, etc.

(Not insisting though -- probably it's clear enough that way as well...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done! in the latest batch of commits

path, sockaddr.sun_path.len() - 1);
sockaddr.sun_family = libc::AF_UNIX as u16;
let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr())
as usize);
Copy link
Contributor

Choose a reason for hiding this comment

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

While this happens to work on Linux and FreeBSD, I don't think it's really generic... As I said, this would probably require some pointer arithmetic -- but I still think the right way to handle this is to just use sizeof sockaddr_un, like in the Linux man page example, rather than trying to determine the actually used size dynamically.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Used sizeof(sockaddr_un) in the latest batch of commits.

@dlrobertson dlrobertson force-pushed the support-freebsd branch 4 times, most recently from 601b464 to b9c149d Compare October 11, 2016 03:04
@antrik
Copy link
Contributor

antrik commented Oct 19, 2016

Apart from the pending question regarding handling of platform conditionals, I'd say this is good to go :-)

@valpackett
Copy link

Thank you for doing this work! Got Webrender working on FreeBSD :)

Rename platform/linux to platform/unix in preparation to adding support
for FreeBSD.
Instead of directly using ptr::offset and the equivalent of CMSG_DATA in
glibc on Linux, create a CMSG_DATA function that should work on Linux
and FreeBSD. This should not cause any side effects, but should make it
easier if we should introduce support for another OS that may have a
different implementation of CMSG_DATA.
Add the new_sockaddr_un function that builds a sockaddr_un struct in a
platform agnostic way.
Add OS specific types that address alignment problems and their
respective libc definitions.
@dlrobertson
Copy link
Contributor Author

Updated with the suggested patch splits.

@antrik
Copy link
Contributor

antrik commented Oct 25, 2016

Great, let's get this landed :-)

@pcwalton
Copy link
Contributor

@bors-servo: r+

@bors-servo
Copy link
Contributor

📌 Commit 4886205 has been approved by pcwalton

@bors-servo
Copy link
Contributor

⌛ Testing commit 4886205 with merge 3250a60...

bors-servo pushed a commit that referenced this pull request Oct 25, 2016
Support Freebsd

Add support for FreeBSD and rename `linux` module to `unix`.

**NB:** Some tests are still currently failing on freebsd. I believe most of which have to do with system limits e.g. (`platform::medium_data` blocks on a `send_followup_fragment` due to system limits and never recovers).
@bors-servo
Copy link
Contributor

☀️ Test successful - status-appveyor, status-travis

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.

6 participants