Reputation: 2934
So I have been trying to find some sort of information on how GNU screen actually works at a high without actually having to read through the source code but I have been unable to do so.
What does screen do that it is able to stick around even when a terminal session is closed? Does it run as a daemon or something and everyone who invokes screen just connects to it and then it finds which pseudo tty session to attach to or does it do something completely different?
Upvotes: 6
Views: 1279
Reputation: 25605
I haven't studied Screen itself in depth, but I wrote a program that was inspired by it on the user end and I can describe how mine works:
The project is my terminal emulator which has an emulation core, a gui front end, a terminal front end, and the two screen-like components: attach.d and detachable.d.
https://github.com/adamdruppe/terminal-emulator
attach.d is the front end. It connects to a particular terminal through a unix domain socket and forwards the output from the active screen out to the actual terminal. It also sends messages to the backend process telling it to redraw from scratch and a few other things (and more to come, my thing isn't perfect yet).
https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d
My terminal.d library provides an event loop that translates terminal input and signals. One of them is HUP signals, which are sent when the controlling terminal is closed. When it sees that, the front-end attach process closes, leaving the backend process in place:
https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d#L709
When attach starts up and cannot connect to an existing process, it forks and creates a detachable backend:
https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d#L454
By separating the front end and backend into separate processes, closing one leaves the other intact. Screen does this too: run a ps aux | grep -i screen. The all-caps SCREEN processes are backends. Frontends are lowercase screen processes.
me 3479 0.0 0.0 26564 1416 pts/14 S+ 19:01 0:00 screen
root 3480 0.0 0.0 26716 1528 ? Ss 19:01 0:00 SCREEN
There, I just started screen
and you can see the two separate processes. screen forked and made SCREEN, which actually holds the state. Detaching kills process 3479, but leaves process 3480 in place.
The backend of mine is a full blown terminal emulator that maintains all internal state:
https://github.com/adamdruppe/terminal-emulator/blob/master/detachable.d
Here: https://github.com/adamdruppe/terminal-emulator/blob/master/detachable.d#L140 it reads from the socket attach talks to, reads the message, and forwards it to the application as terminal input.
The redraw method, here: https://github.com/adamdruppe/terminal-emulator/blob/master/detachable.d#L318 loops through its internal screen buffer - stored as an array of attributes and characters - and writes them back out to the attached terminal.
You can see both source files aren't terribly long - most the work is done in the terminal emulator core. https://github.com/adamdruppe/terminal-emulator/blob/master/terminalemulator.d and, to a lesser extent, my terminal client library (think: custom ncurses lib) https://github.com/adamdruppe/arsd/blob/master/terminal.d
Attach.d you can see also manages multiple connections, using select
to loop through each open socket, and only drawing the active screen: https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d#L300
My program runs a separate backend process for each individual terminal screen. GNU screen uses one process for a whole session, which may have multiple screens. My guess is screen does more work in the backend than I do, but it is basically the same principle: watch for input on each pty and update an internal screen buffer. When you run screen -r
to attach to it, it connects through a named pipe - a FIFO in the file system (on my gnu screen config, they are stored in /tmp/screens
) instead of the unix socket I used, but same principle - it gets the state dumped to the screen, then carries on forwarding info back and forth.
Anyway, I've been told my source is easier to read than screens' and xterm's, and while not identical, they are similar, so maybe you can get more ideas browsing through them too.
Upvotes: 4
Reputation: 126378
There's a lot of potential questions in this question, so I'm going to concentrate on just one:
What does screen do that it is able to stick around even when a terminal session is closed?
Screen catches HUP signals, so it doesn't automatically exit when its controlling terminal goes away. Instead, when it gets a HUP, it goes into background mode (since it no longer has an actual terminal attached) and waits. When you start screen with various -d/-D/-r/-R/-RR options, it looks for an already running screen process (possibly detached after having received a HUP, and/or possibly detaching it directly by sending it a HUP) and takes over the child terminal sessions of that screen process (a cooperative process whereby the old screen process sends all the master PTYs to the new process for it to manage, before exiting).
Upvotes: 6