1

In particular, I'm writing an interpreter, and I'd like it to run source code from STDIN if no source file is given.

So I wrote a tiny program that is basically just a loop that, upon each iteration, reads a line from STDIN and adds it to a linked list, then prints the list when it's done. When I pipe a file to this program, i.e. cat my_awesome_file | ./tiny_program, it does in fact print the list and subsequently exit. How does it know to do this? Does cat send a sigint to tiny_program? Is there some sentinel byte (maybe the null byte) that conveys "hey, I'm done sending you stuff now"?

So in summary, my program is working fine, but I don't really know why it's working fine, and I'd very much like to.

Here's my tiny program, in rust. The exact code is probably not relevant, but maybe someone will find it helpful.

fn main() {
    let mut ll: LinkedList<String> = LinkedList::new();
    for line in std::io::stdin().lines() {
        ll.push_back(line.unwrap());
    }
    println!("{:?}", ll);
}
mobotsar
  • 13
  • 3
  • Can you please post your code as well? Please provide [MCVE](https://stackoverflow.com/help/minimal-reproducible-example). Also refer [How to ask a good question](https://stackoverflow.com/help/how-to-ask) – Gaurav Pathak Mar 05 '23 at 09:18
  • Generally you read until EOF is reached. – Retired Ninja Mar 05 '23 at 09:19
  • When `cat` finishes outputting, it terminates and no longer adds input to the pipe. Your program drains the pipe as its input. When there's no more to be drawn out of the pipe, there's no more to be drawn out of the pipe. – Fe2O3 Mar 05 '23 at 09:24
  • 1
    https://stackoverflow.com/questions/22210534/why-does-the-read-end-of-a-pipe-read-eof-only-if-the-write-end-is-closed – Support Ukraine Mar 05 '23 at 10:01
  • https://unix.stackexchange.com/questions/389373/how-can-pipe-producer-tell-pipe-consumer-it-has-reached-end-of-file-un-name – Support Ukraine Mar 05 '23 at 10:03
  • @GauravPathak There's nothing to reproduce really, so I don't think MCRE applies. I suppose I could post my code, but again, I'm asking a general question, so I don't think it's relevant. – mobotsar Mar 05 '23 at 10:15
  • These seems apropos: [**Useless use of cat?**](https://stackoverflow.com/questions/11710552/useless-use-of-cat) and [**Useless Use of Cat Award**](https://porkmail.org/era/unix/award) – Andrew Henle Mar 05 '23 at 15:03

1 Answers1

0
  • Programs communicate with kernel.
  • Kernel does all the transfer of bytes and keeps state
  • Shell creates a pipe().
  • Shell fork() two processes as part of pipeline cat and ./tiny_program.
  • The processes have dup2 the file descriptoes from pipe().
  • cat write()s to the pipe from one side.
  • Kernel receives bytes from write(), saves them to a temporary storage.
  • ./tiny_program read()s from the pipe from the other side.
  • Kernel sees if there are bytes in temporary storage and returns them.
  • cat does close()
  • Kernel sees that close() was done, and marks that the pipe is closed.
  • ./tiny_program does read()
  • Kernel sees that there are no more bytes in temporary storage. Beacuse the pipe is closed, kernel returns 0.
  • Because ./tiny_program is reading in blocking mode, 0 from read() means the stream is closed.
  • ./tiny_program terminates.

Does cat send a sigint to tiny_program?

No.

Is there some sentinel byte (maybe the null byte) that conveys "hey, I'm done sending you stuff now"?

No, there is a state in kernel memory that keeps track of the pipe state. https://github.com/torvalds/linux/blob/master/fs/pipe.c#L720

KamilCuk
  • 120,984
  • 8
  • 59
  • 111