How does Terminal read from stdout and draw the text on-screen?

bash, c, linux, macos, unix

Solution

The magic part here that you don't seem to be aware of is the kernel's tty layer.

Each terminal window you open corresponds to a pseudoterminal device — for instance, `/dev/ttys001` is a name for one such device on Mac OS X. By default, any process that's running in a terminal and which doesn't have its input/output redirected from/to somewhere else, its standard input, output, and error are all set to one of these devices. For instance, if I run `lsof` on a `cat` process running in a terminal, I see:

COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF     NODE NAME
...
cat     52919 user    0u   CHR   16,5    0t4562     3313 /dev/ttys005
cat     52919 user    1u   CHR   16,5    0t4562     3313 /dev/ttys005
cat     52919 user    2u   CHR   16,5    0t4562     3313 /dev/ttys005

When a process writes to a pseudoterminal slave device, the output is routed to the process holding the master end of the connection (in this case, your terminal application), which can read it. Similarly, when a terminal application writes to a pseudoterminal master device, the data becomes available to any process that's reading from the corresponding slave device.

There are a few other tricks involved with pseudoterminal devices. Most notably, they have an inherent size in rows and columns, which an application running in them can query, they can perform certain simple translations on data passing through them (for instance, CR to CR/LF, backspace to DEL, and other such things), and they can generate signals when certain characters are seen (e.g, Ctrl-C generates an interrupt signal to the foreground process). There's a lot of weird historical subtleties here, but the point is that the kernel's tty layer is where most of this behavior exists.

Pseudoterminal devices are created using the `forkpty()` libc function. The details of how this works behind the scenes vary from platform to platform, and can get pretty hairy, so I won't dig into the details.

Problem

I have a general question about how the terminal and processes work. From any process, if I write to stdout (i.e. file descriptor 2), it gets drawn on the terminal window. My question is, how is this actually implemented? Is stdout an actual 'dummy' file somewhere that the terminal keeps on reading from and drawing the content on screen? Or is there some kind of IPC between the process/stdout stream and the Terminal? Note that when I say terminal, I mean some general GUI terminal/console, such as Terminal on the Mac. P.S. If this question is unclear, let me know and I will happily try to explain again :) Thanks!

Original source