-
Notifications
You must be signed in to change notification settings - Fork 677
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
Implement sendfile on FreeBSD and Darwin #901
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to the comments I made inline, please add a CHANGELOG entry.
src/sys/sendfile.rs
Outdated
#[allow(missing_debug_implementations)] | ||
#[allow(missing_copy_implementations)] | ||
#[repr(C)] | ||
pub struct SfHdTr(libc::sf_hdtr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add a PhantomData
field to keep sf_hdtr
's pointers from dangling. See AioCb::from_mut_slice
in src/sys/aio.rs for an example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Does it look correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
src/sys/sendfile.rs
Outdated
pub struct SfFlags: c_int { | ||
SF_NODISKIO; | ||
SF_MNOWAIT; | ||
// SF_NOCACHE; // TODO: not yet exported by libc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you opened a PR with libc for SF_NOCACHE
support? If not, you should. It's very easy to get PRs accepted to libc. When you do, you should also include SF_USER_READAHEAD
, which is new in FreeBSD 12.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working on a PR against libc now. The tests fail when I add the FreeBSD 12 constant and run them on my FreeBSD 11.1 machine. Once I figure that out, I'll submit it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because libc's tests run on FreeBSD 11.1. If you're adding a 12.0-specific symbol, you'll have to add it to the skip_fn
section of libc-test/build.rs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/sys/sendfile.rs
Outdated
libc_bitflags!{ | ||
pub struct SfFlags: c_int { | ||
SF_NODISKIO; | ||
SF_MNOWAIT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SF_MNOWAIT
is obsolete in FreeBSD 11.0 and above. The last release that makes use of it, 10.4, goes EoL on Oct 31 of this year. So I'd rather not expose this symbol in Nix unless there is specific demand.
src/sys/sendfile.rs
Outdated
} | ||
|
||
#[cfg(target_os = "freebsd")] | ||
pub fn sendfile(in_fd: RawFd, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add some usage documentation?
test/test_sendfile.rs
Outdated
let (mut rd, wr) = UnixStream::pair().unwrap(); | ||
|
||
// Call the test method | ||
let (res, bytes_written) = sendfile(tmp.as_raw_fd(), wr.as_raw_fd(), body_offset as off_t, 0, Some(&hdtr), SfFlags::empty(), 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap to 80 columns, please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I just run rustfmt
on the files I've touched?
src/sys/sendfile.rs
Outdated
pub fn sendfile(in_fd: RawFd, | ||
out_sock: RawFd, | ||
offset: off_t, | ||
count: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be more Rusty for count
to be an Option<usize>
instead of giving a special meaning to 0
.
Thanks for the very quick feedback! I'll update this PR soon. |
src/sys/sendfile.rs
Outdated
#[allow(missing_debug_implementations)] | ||
#[allow(missing_copy_implementations)] | ||
#[repr(C)] | ||
pub struct SfHdTr(libc::sf_hdtr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to see a better name for this struct compared to the cryptic shorthand libc uses. SendfileHeader
I think would work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about SendfileHeaderTrailer
?
src/sys/sendfile.rs
Outdated
pub struct SfFlags: c_int { | ||
SF_NODISKIO; | ||
SF_SYNC; | ||
// SF_USER_READAHEAD; // TODO: waiting on libc release |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nix uses a git dependency on libc (except when we release), so you can go ahead and enable these now.
src/sys/sendfile.rs
Outdated
#[allow(missing_debug_implementations)] | ||
#[allow(missing_copy_implementations)] | ||
#[repr(C)] | ||
pub struct SfHdTr(libc::sf_hdtr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
I would still like to see some doc comments and a CHANGELOG entry. I would consider Dragonfly support to be optional, since we don't test that platform anyway. |
I haven't been able to build rustc on DragonFly after several tries, so I will not implement that in this PR. I'll add the doc comments, add the change log entry, clean up my TODOs, rebase, and ping you when it's ready. Thanks again! |
src/sys/sendfile.rs
Outdated
|
||
libc_bitflags!{ | ||
pub struct SfFlags: c_int { | ||
SF_NODISKIO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add some documentation for the flags?
src/sys/sendfile.rs
Outdated
/// | ||
/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. | ||
/// | ||
/// For more information, see `man 2 sendfile` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a link, like other man pages references throughout our docs.
src/sys/sendfile.rs
Outdated
/// included in the returned count of bytes written. The values of `offset` and `count` do | ||
/// not apply to headers or trailers. | ||
/// | ||
/// `readahead` specifies how many pages may be cached in memory ahead of the page currently |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/how many pages may be cached/the minimum number of pages to cache/
test/test_sendfile.rs
Outdated
tmp.write_all(body.as_bytes()).unwrap(); | ||
|
||
// Prepare headers and trailers for sendfile | ||
let headers: Vec<IoVec<&[u8]>> = header_strings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense for the API to accept a slice of slices instead of a slice of IoVec
s? That would simplify the user's code. In fact, if you did this, then SendfileHeaderTrailer
wouldn't even need to be public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a slice of byte slices? I feel like it makes the API even less obtuse.
@asomers ready for another look! |
src/sys/sendfile.rs
Outdated
pub struct SendfileHeaderTrailer<'a>(libc::sf_hdtr, PhantomData<&'a [IoVec<&'a [u8]>]>); | ||
struct SendfileHeaderTrailer<'a>( | ||
libc::sf_hdtr, | ||
Option<Vec<IoVec<&'a [u8]>>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it necessary to store the Option<Vec<
fields in SendfileHeaderTrailer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it's creating the IoVec
structs from byte slices, it's now the logical owner of those structs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It still doesn't own the data, however. PhantomData
should be sufficient to keep the caller from dropping the byte slices. Or is there something I'm missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't own the byte slices, but it does own all of the IoVec
instances, which do occupy memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, that makes sense. In that case, this PR LGTM. All it needs is a squash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squashed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved! I'll leave it up for a few days, in case @Susurrus has any comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few minor style fixups on my end. r+ once these are all corrected.
} | ||
} | ||
|
||
cfg_if! { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need a new one I don't think and could be bundled into the above macro, yes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header/trailer struct is the same across FreeBSD and Darwin, but the flags and function signatures are different, so they can't share all code. I could nest the ifs, but this felt like it caused less rightward drift.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was referring only to the cfg_if!
macro instance. Can you only have one if/else chain within each macro instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, if I try to put multiple independent if/else chains inside a single macro block, it won't compile. :(
src/sys/sendfile.rs
Outdated
/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. | ||
/// | ||
/// For more information, see [the sendfile(2) man page.](http://man7.org/linux/man-pages/man2/sendfile.2.html) | ||
#[cfg(any(target_os = "linux", target_os = "android"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please alphabetize the OSes listed here.
test/test_sendfile.rs
Outdated
|
||
#[cfg(any(target_os = "linux", target_os = "android"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please alphabetize the target OS list here.
test/test_sendfile.rs
Outdated
use nix::unistd::{close, pipe, read}; | ||
use nix::sys::sendfile::sendfile; | ||
cfg_if! { | ||
if #[cfg(any(target_os = "linux", target_os = "android"))] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please alphabetize the target OS list here.
test/test_sendfile.rs
Outdated
if #[cfg(any(target_os = "linux", target_os = "android"))] { | ||
use nix::unistd::{close, pipe, read}; | ||
} | ||
else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put else
expressions on the same line as the closing brace as suggested by the style guidelines.
src/sys/sendfile.rs
Outdated
(Errno::result(return_code).and(Ok(())), bytes_sent) | ||
} | ||
} | ||
else if #[cfg(any(target_os = "ios", target_os = "macos"))] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put else
expressions on the same line as the closing brace as suggested by the style guidelines.
@Susurrus style comments addressed! Ready for another look. |
bors r+ |
901: Implement sendfile on FreeBSD and Darwin r=Susurrus a=morrowa This PR exposes the `sendfile` system call on libc's supported BSD-likes: * FreeBSD * Darwin (macOS/iOS) DragonFly could be supported in the future, but I was unable to build rustc to test. Note that NetBSD has no equivalent system call. Co-authored-by: Andrew Morrow <[email protected]>
Build failed |
The test failure is weird. It looks like Nix's code is wrong, and AFAICT this should've been failing ever since 5378945, but it never failed until now. There have been no recent changes in either libc or japaric/cross that look related. I don't know why it just began to fail. |
A recent PR merged into libc changed the |
You're right; I just couldn't find that with git blame for some reason. |
Please see #906 for a fix. |
bors r+ |
901: Implement sendfile on FreeBSD and Darwin r=Susurrus a=morrowa This PR exposes the `sendfile` system call on libc's supported BSD-likes: * FreeBSD * Darwin (macOS/iOS) DragonFly could be supported in the future, but I was unable to build rustc to test. Note that NetBSD has no equivalent system call. Co-authored-by: Andrew Morrow <[email protected]>
This PR exposes the
sendfile
system call on libc's supported BSD-likes:DragonFly could be supported in the future, but I was unable to build rustc to test.
Note that NetBSD has no equivalent system call.