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.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.