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

Add POSIX AIO support #483

Merged
merged 3 commits into from
Jan 26, 2017
Merged

Add POSIX AIO support #483

merged 3 commits into from
Jan 26, 2017

Conversation

asomers
Copy link
Member

@asomers asomers commented Dec 3, 2016

POSIX AIO is a standard for asynchronous file I/O. Read, write, and
fsync operations can all take place in the background, with completion
notification delivered by a signal, by a new thread, by kqueue, or not
at all.

The SigEvent class, used for AIO notifications among other things, is
also added.

@asomers
Copy link
Member Author

asomers commented Dec 4, 2016

All failures are actually in the dependent gcc crate, which no longer compiles with rust 1.7.0.

@homu
Copy link
Contributor

homu commented Dec 16, 2016

☔ The latest upstream changes (presumably #478) made this pull request unmergeable. Please resolve the merge conflicts.

POSIX AIO is a standard for asynchronous file I/O.  Read, write, and
fsync operations can all take place in the background, with completion
notification delivered by a signal, by a new thread, by kqueue, or not
at all.  This commit supports all standard AIO functions.  However,
lio_listio is disabled on macos because it doesn't seem to work, even
though the syscall is present.

The SigEvent class, used for AIO notifications among other things, is
also added.

Also, impl AsRef for TimeVal and TimeSpec
@asomers
Copy link
Member Author

asomers commented Dec 22, 2016

Could I please get some review of this PR?

// lio_listio wouldn't work, because that function needs a slice of AioCb,
// and they must all be the same type. We're basically stuck with using an
// unsafe function, since aio (as designed in C) is an unsafe API.
pub unsafe fn from_slice(fd: RawFd, offs: off_t, buf: &[u8],
Copy link
Member

Choose a reason for hiding this comment

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

With the version of these functions that take references to buffers, I wonder if it would be reasonable to do something to ensure that the lifetime of the reference is at least as long as the lifetime of the AioCb. Without this, there buffer could go out of scope in the calling context and we would be working with an invalid pointer.

I think this would typically be done with something like PhantomData (when not storing the reference itself).

Errno::result(unsafe { libc::aio_fsync(mode as ::c_int, p) }).map(drop)
}

/// Asynchously reads from a file descriptor into a buffer
Copy link
Member

Choose a reason for hiding this comment

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

nit: Typo with "Asynchronously"

@posborne
Copy link
Member

Hi @asomers. Deep apologies for the delay in getting you a review on this. Having AIO support in nix will be a wonderful addition and this looks like it will work great.

I think my main concern right now is with the validity of buffers we are using for doing asynchronous reads/writes and ensuring that the lifetime of the buffer is at least as long as the asynchronous operation -- Without this, I think the kernel could easily end up stomping on memory (which would result in all manner of bad things). Is this concern warranted?

I have mixed feelings on the AIO subsystem in general (my experience with Linux only) and am not sure where it is headed. That being said, there are cases where it is beneficial for it to be used today and will be happy to accept this change (once we discuss a bit more).

@asomers
Copy link
Member Author

asomers commented Jan 16, 2017

Point taken, @posborne . I'll try to fix the buffer lifetime issue. Regarding the AIO subsystem: I can understand why you're skeptical, because it's not well implemented on Linux. On Linux, POSIX AIO performs poorly and the nonstandard libaio performs well. However, in the BSD world, POSIX AIO performs well and there is no libaio.

Unfortunately, libaio does not have a compatible API at all. The differences are even worse for higher level libraries. mio and tokio-core basically need completely different implementations to use posix AIO vs libaio.

But POSIX AIO does exist and work on Linux, and it works well on the BSDs, so I think it's worth including in nix.

@posborne
Copy link
Member

Thanks for the summary @asomers and points well taken. I agree that exposing the Posix AIO interface (even if not performant with the glibc userspace implementation on linux) is the right thing to do in nix. Mio or other libraries should be the ones to decide what abstraction to use on which host operating systems.

@posborne
Copy link
Member

Excellent, feeling better about this now that we track lifetimes.

I think it would be good to consider the following additional improvements in the future. Let me know your thoughts:

  1. Rather than having freestanding functions like aio_read, move these to be on the callback as you need to pass that in as a parameter anyway and it creates a more fluent API.
  2. Consider automatic cancellation or other action on drop of an AioCb. Right now, we are able to "leak" these very easily.

@homu r+

@homu
Copy link
Contributor

homu commented Jan 26, 2017

📌 Commit b740156 has been approved by posborne

@homu homu merged commit b740156 into nix-rust:master Jan 26, 2017
homu added a commit that referenced this pull request Jan 26, 2017
Add POSIX AIO support

POSIX AIO is a standard for asynchronous file I/O.  Read, write, and
fsync operations can all take place in the background, with completion
notification delivered by a signal, by a new thread, by kqueue, or not
at all.

The SigEvent class, used for AIO notifications among other things, is
also added.
@homu
Copy link
Contributor

homu commented Jan 26, 2017

⚡ Test exempted - status

@asomers
Copy link
Member Author

asomers commented Jan 26, 2017

Good idea regarding class vs instance methods, @posborne. I'll take a swing at it. I think there's also some runtime safety checks we could add, if we're willing to expand the AioCb structure. For example, at runtime we could prohibit calling aio_read on an AioCb created with from_slice. That kind of check can't be performed at compile time without breaking lio_listio.

@posborne
Copy link
Member

@asomers I think the runtime check sounds reasonable.

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

3 participants