Why read_to_string hung when there's readable event on the file fd?

To understand Mio, I wrote a small example:

I use mkfifo p to make a named pipe, and in one of the terminal windows, I use:
cat > p to send content to the pipe

In the code,

  1. I opened the file,
  2. add the file fd to the epoll's interest list.
  3. epoll_wait to wait for events

I can correctly get the readable event:

Event { token: Token(1), readable: true, writable: false, error: false, read_closed: false, write_closed: false, priority: false, aio: false, lio: false }

However, when I tried to file::read_into_string, the process hung.
I tried to trace the code and it uses libc to read the file. As I'm fairly new to Rust, I can't get useful errors from the result.

Any suggestions? Thanks in advance.

use std::error::Error;
use std::io::Read;
use std::os::unix::io::AsRawFd;

use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interest, Poll, Token};

// Some tokens to allow us to identify which event is for which socket.
const SERVER: Token = Token(0);
const File: Token = Token(1);

// fn main() -> Result<(), Box<dyn Error>> {
fn main() {
    let mut file = std::env::args().nth(1).unwrap();
    let mut top_poll = Poll::new().unwrap();
    use std::fs::File;
    let mut f = File::open(file).unwrap();

    use mio::unix::SourceFd;
    use std::os::unix::io::AsRawFd;

    top_poll.registry().register(&mut SourceFd(&f.as_raw_fd()), File, Interest::READABLE);

    let mut top_events = Events::with_capacity(128);

    loop {
        // top epoll
        top_poll.poll(&mut top_events, None).unwrap();

        let mut cont = String::new();
        for e in top_events.iter() {
            println!("{:?}", e);

            println!("start to read file");
            let flen = f.read_to_string(&mut cont).unwrap();
            println!("{:?}, content {}", flen, cont);

        }
    }
}

The read_to_string method keeps reading until the thing you're reading from is closed/you reach the end. It probably didn't return because the pipe isn't closed.

Additionally, when using mio, you should only do a single read and then go back to the loop and wait for readiness again. However, the read_to_string method will perform many reads.

Thx a lot, I did see that read_to_string is kept looping for data.
Is there a single read interface in std::fs? or do I need to use libc to do some unsafe Rust on the file socket?

   let flen = f.read(&mut buffer).unwrap();

I was able to read fixed length to get the example working

The read method is used to do a single read. However, it is not "fixed length", as you called it. It returns the length of the read - the provided array is merely the maximum length of the read.

yea, my words are kinda misleading, but thanks for the clarification.