Skip to content

Add Async::new_nonblocking and avoid needless set_nonblocking calls #159

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

Merged
merged 2 commits into from
Oct 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 54 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,8 +636,8 @@ impl<T: AsFd> Async<T> {
/// This method will put the handle in non-blocking mode and register it in
/// [epoll]/[kqueue]/[event ports]/[IOCP].
///
/// On Unix systems, the handle must implement `AsRawFd`, while on Windows it must implement
/// `AsRawSocket`.
/// On Unix systems, the handle must implement `AsFd`, while on Windows it must implement
/// `AsSocket`.
///
/// [epoll]: https://en.wikipedia.org/wiki/Epoll
/// [kqueue]: https://en.wikipedia.org/wiki/Kqueue
Expand All @@ -656,14 +656,33 @@ impl<T: AsFd> Async<T> {
/// # std::io::Result::Ok(()) });
/// ```
pub fn new(io: T) -> io::Result<Async<T>> {
let fd = io.as_fd();

// Put the file descriptor in non-blocking mode.
set_nonblocking(fd)?;
set_nonblocking(io.as_fd())?;

Self::new_nonblocking(io)
}

/// Creates an async I/O handle without setting it to non-blocking mode.
///
/// This method will register the handle in [epoll]/[kqueue]/[event ports]/[IOCP].
///
/// On Unix systems, the handle must implement `AsFd`, while on Windows it must implement
/// `AsSocket`.
///
/// [epoll]: https://en.wikipedia.org/wiki/Epoll
/// [kqueue]: https://en.wikipedia.org/wiki/Kqueue
/// [event ports]: https://illumos.org/man/port_create
/// [IOCP]: https://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports
///
/// # Caveats
///
/// The caller should ensure that the handle is set to non-blocking mode or that it is okay if
/// it is not set. If not set to non-blocking mode, I/O operations may block the current thread
/// and cause a deadlock in an asynchronous context.
pub fn new_nonblocking(io: T) -> io::Result<Async<T>> {
// SAFETY: It is impossible to drop the I/O source while it is registered through
// this type.
let registration = unsafe { Registration::new(fd) };
let registration = unsafe { Registration::new(io.as_fd()) };

Ok(Async {
source: Reactor::get().insert_io(registration)?,
Expand Down Expand Up @@ -711,8 +730,8 @@ impl<T: AsSocket> Async<T> {
/// This method will put the handle in non-blocking mode and register it in
/// [epoll]/[kqueue]/[event ports]/[IOCP].
///
/// On Unix systems, the handle must implement `AsRawFd`, while on Windows it must implement
/// `AsRawSocket`.
/// On Unix systems, the handle must implement `AsFd`, while on Windows it must implement
/// `AsSocket`.
///
/// [epoll]: https://en.wikipedia.org/wiki/Epoll
/// [kqueue]: https://en.wikipedia.org/wiki/Kqueue
Expand All @@ -731,16 +750,35 @@ impl<T: AsSocket> Async<T> {
/// # std::io::Result::Ok(()) });
/// ```
pub fn new(io: T) -> io::Result<Async<T>> {
let borrowed = io.as_socket();

// Put the socket in non-blocking mode.
set_nonblocking(borrowed)?;
set_nonblocking(io.as_socket())?;

Self::new_nonblocking(io)
}

/// Creates an async I/O handle without setting it to non-blocking mode.
///
/// This method will register the handle in [epoll]/[kqueue]/[event ports]/[IOCP].
///
/// On Unix systems, the handle must implement `AsFd`, while on Windows it must implement
/// `AsSocket`.
///
/// [epoll]: https://en.wikipedia.org/wiki/Epoll
/// [kqueue]: https://en.wikipedia.org/wiki/Kqueue
/// [event ports]: https://illumos.org/man/port_create
/// [IOCP]: https://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports
///
/// # Caveats
///
/// The caller should ensure that the handle is set to non-blocking mode or that it is okay if
/// it is not set. If not set to non-blocking mode, I/O operations may block the current thread
/// and cause a deadlock in an asynchronous context.
pub fn new_nonblocking(io: T) -> io::Result<Async<T>> {
// Create the registration.
//
// SAFETY: It is impossible to drop the I/O source while it is registered through
// this type.
let registration = unsafe { Registration::new(borrowed) };
let registration = unsafe { Registration::new(io.as_socket()) };

Ok(Async {
source: Reactor::get().insert_io(registration)?,
Expand Down Expand Up @@ -1479,7 +1517,8 @@ impl Async<TcpStream> {

// Begin async connect.
let socket = connect(sock_addr, domain, Some(rn::ipproto::TCP))?;
let stream = Async::new(TcpStream::from(socket))?;
// Use new_nonblocking because connect already sets socket to non-blocking mode.
let stream = Async::new_nonblocking(TcpStream::from(socket))?;

// The stream becomes writable when connected.
stream.writable().await?;
Expand Down Expand Up @@ -1812,7 +1851,8 @@ impl Async<UnixStream> {
rn::AddressFamily::UNIX,
None,
)?;
let stream = Async::new(UnixStream::from(socket))?;
// Use new_nonblocking because connect already sets socket to non-blocking mode.
let stream = Async::new_nonblocking(UnixStream::from(socket))?;

// The stream becomes writable when connected.
stream.writable().await?;
Expand Down