How does a terminal read from stdout and display text?

I have a general question about how terminals and processes work.

From any process, if I write to stdout (i.e. file descriptor 2), it is typed in a terminal window. My question is, how is this really implemented? Is stdout the actual 'dummy' file somewhere that the terminal continues to read and draw content on the 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 common terminal / GUI console, like Terminal on Mac.

PS If this question is unclear, let me know, and I will be happy to try to explain again :)

Thanks!

+7
source share
3 answers

When you include stdio.h, stdout is the variable defined there.

To quote Wikipedia

stdout - pointer to FILE, which refers to the standard output stream, usually to the display terminal

And, as Russ C mentioned, everything is in the Unix file, so you're right about that.

And obviously , every open unix program has its own output, input and error streams set by default for stdout, stdin, and stderr, respectively. However, they can be changed. Like in a terminal where you redirect standard file input using '<', which you probably do in expressions like

mysql -u root -p dbname < ./data.sql 

I think this does not answer all your questions about the real implementation details, but knowing that the file stream can probably give you a pretty good idea of ​​what is going on.

+3
source

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

Each open terminal window corresponds to a pseudo-terminal device - for example, /dev/ttys001 is the name for one such device in Mac OS X. By default, any process that runs on the terminal and which does not have its input / output redirected from / to another location, its standard input, output, and error are installed on one of these devices. For example, 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 is written to a pseudo-terminal slave, the output is sent to a process that supports the main end of the connection (in this case, your terminal application), which can read it. Similarly, when a terminal application writes to a pseudo-terminal master, data becomes available for any process that is read from the corresponding slave.

There are several other tricks associated with pseudo-terminal devices. In particular, they have their own size in rows and columns, to which the application running in them can be run, they can perform some simple translations of the data passing through them (for example, CR in CR / LF, backspace to DEL and other similar things) , and they can generate signals when certain characters are visible (for example, Ctrl - C generates an interrupt signal for the foreground process). There are many strange historical subtleties, but the fact is that the tty layer of the kernel is where most of this behavior exists.

Pseudo-terminal devices are created using the forkpty() libc function. Details of how this works behind the scenes vary from platform to platform and can be quite hairy, so I won’t go into details.

+3
source

Here is the big picture.

  • A terminal is a device. This is part of the hardware, and you can make things appear on it by writing data to your hardware interface.
  • Operating systems delegate the processing of this (and any hardware device) to the device driver. A device driver essentially offers a device software interface. You can then make things appear on the terminal by invoking this device driver programming interface.
  • On * nix systems, device drivers detect hardware devices that they control as files on the file system. You can open these files and invoke the program interface offered by the device driver (via open, ioctl, close, etc.).
  • The C library has a multi-level I / O system, which is located under them and opens the device driver interface on your behalf. You can do it yourself, but just be aware that any library functions you use do this too.
  • By default, when a process is created, descriptors 0 and 1 open on the terminal device. Therefore, when you write these descriptors, the base driver receives data and talks to a hardware device to visualize the characters on the screen.
  • When you connect the output of a process to another process or redirect the output to a file, the descriptors open again to other devices, such as a channel or file, and the data you write to them gets into the corresponding device driver and, ultimately, the hardware device.
+1
source

All Articles