You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reading from a non blocking PTY main fd that is wrapped in a tokio::fs::File returns EAGAIN when calling any ready function, eg. read. The PTY is created with posix_openpt(OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK). The sub fd of the PTY is opened and some bytes are written to it.
The read fn returns EAGAIN immediately which should never happen on a correctly setup non blocking fd wrapped in File.
use std::os::unix::prelude::{AsRawFd,FromRawFd,IntoRawFd};use nix::{
fcntl::{self,OFlag},
sys::{stat::Mode, termios::SetArg},};#[tokio::main]asyncfnmain() -> anyhow::Result<()>{// Open a new PTY mainlet main_fd = nix::pty::posix_openpt(OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK)?;// Ensure that the fd is non-blockinglet flags = nix::fcntl::fcntl(main_fd.as_raw_fd(), fcntl::FcntlArg::F_GETFL)?;assert!(flags & fcntl::OFlag::O_NONBLOCK.bits() != 0);
nix::pty::grantpt(&main_fd)?;
nix::pty::unlockpt(&main_fd)?;// Set raw modeletmut termios = nix::sys::termios::tcgetattr(main_fd.as_raw_fd())?;
nix::sys::termios::cfmakeraw(&mut termios);
nix::sys::termios::tcsetattr(main_fd.as_raw_fd(),SetArg::TCSANOW,&termios)?;// Get the name of the sub e.g /dev/pts/4 and open itlet sub_name = unsafe{ nix::pty::ptsname(&main_fd)}.unwrap();let _ = fcntl::open(sub_name.as_str(),OFlag::O_RDWR,Mode::empty()).unwrap();// Write some bytes to the pty subdbg!(nix::unistd::write(main_fd.as_raw_fd(), b"hello\n"))?;// Wrap the main fd in a Fileletmut file = unsafe{ tokio::fs::File::from_raw_fd(main_fd.into_raw_fd())};let buf = &mut[0u8;16];loop{dbg!(file.read(buf).await)?;}Ok(())}
The read returns one or more times some Ok(n) with n >=1. Finally the program waits for more bytes to become available on main which never happens.
Instead, this happened:
The read.await resolves to EAGAIN.
I poked around and used AsyncFd for wrapping the RawFd. Using the exact same main fd and calling readable seems to work fine:
<see above>
// Write some bytes to the pty subdbg!(nix::unistd::write(main_fd.as_raw_fd(), b"hello\n"))?;// let mut file = unsafe { tokio::fs::File::from_raw_fd(main_fd.into_raw_fd()) };// let buf = &mut [0u8; 16];// loop {// dbg!(file.read(buf).await)?;// }let fd = tokio::io::unix::AsyncFd::new(main_fd.into_raw_fd())?;loop{let _ = dbg!(fd.readable().await?);}
Output:
Finished dev [unoptimized + debuginfo] target(s) in 1.15s
Running `target/debug/fdids`
[src/main.rs:31] nix::unistd::write(main_fd.as_raw_fd(), b"hello\n") = Ok(
6,
)
<waits here forever>
In the application I'm writing I implemented the read with AsyncFd with try_io and unistd::read etc... which is a lot of nasty code with buffer index handling etc which I would like to avoid by wrapping the fd in something that implements AsyncRead.
Probably this is some speciality Unix/Linux has prepared with PTYs.
The text was updated successfully, but these errors were encountered:
The tokio::fs::File utility is for reading actual files, which cannot be read in a non-blocking manner. Therefore, it offloads the blocking reads to a separate thread pool. You should not use it for FDs that are not files.
Version
1.16.1 9c688ec
Platform
5.10.0-8-amd64 #1 SMP Debian 5.10.46-4 (2021-08-03) x86_64 GNU/Linux
Description
Reading from a non blocking PTY main fd that is wrapped in a
tokio::fs::File
returns EAGAIN when calling any ready function, eg. read. The PTY is created with posix_openpt(OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK). The sub fd of the PTY is opened and some bytes are written to it.The read fn returns
EAGAIN
immediately which should never happen on a correctly setup non blocking fd wrapped inFile
.I tried this code:
Output:
I expected to see this happen:
The
read
returns one or more times someOk(n)
withn >=1
. Finally the program waits for more bytes to become available onmain
which never happens.Instead, this happened:
The
read.await
resolves toEAGAIN
.I poked around and used AsyncFd for wrapping the
RawFd
. Using the exact same main fd and calling readable seems to work fine:Output:
In the application I'm writing I implemented the read with
AsyncFd
withtry_io
andunistd::read
etc... which is a lot of nasty code with buffer index handling etc which I would like to avoid by wrapping the fd in something that implementsAsyncRead
.Probably this is some speciality Unix/Linux has prepared with PTYs.
The text was updated successfully, but these errors were encountered: