Comment 122 for bug 439138

Revision history for this message
Tom Jaeger (thjaeger) wrote :

Scott was kind enough to provide some background on this bug in the #upstart channel:

<Keybuk> in Linux, we have consoles
<Keybuk> but really we mean Virtual Terminals (VTs)
<Keybuk> and we have TTYs too
<Keybuk> not to mention Pseudo-Terminals
<Keybuk> (PTYs)
<Keybuk> it's all a bit of the kind of jumble sale you get after 40 years of different solutions to different problems
<Keybuk> we can lump them together under the description "terminals" for the next bit
<Keybuk> we also have processes
<Keybuk> now, processes have a lot of odd little details
<Keybuk> they have a parent
<Keybuk> they have a session
<Keybuk> and a session has a foreground process group
<Keybuk> and a background process group
<Keybuk> now Stevens devotes an entire chapter for this
<Keybuk> and nobody but me apparently understands it ;)
<Keybuk> (and hopefully the guy who maintains the kernel side)
<Keybuk> but it works something like that
<Keybuk> each process is part of a session
<Keybuk> a process may begin a new session by calling setsid()
<Keybuk> every process that init creates is in its own session
<Keybuk> the process is also then the leader of the foreground process group of that session
<Keybuk> new processes are also in that session
<Keybuk> and in that process group
<Keybuk> unless otherwise placed into a new process group
<Keybuk> (setpgrp)
<Keybuk> any new process group is a background process group
<Keybuk> so now, you have a bunch of sessions
<Keybuk> each session has a bunch of process groups, one of which is the foreground process group
<Keybuk> each process group has a bunch of processes, one of which is the leader
<Keybuk> so this all has to do, fundamentally, with terminals
<Keybuk> and who gets the signals
<Keybuk> when the leader of the foreground process group of a session opens a terminal device (without O_NOCTTY) that becomes the CONTROLLING TERMINAL of that process group
<Keybuk> (in fact of that session)
<Keybuk> the terminal and the session become bound to each other
<Keybuk> you can fake this another way by opening a terminal device without O_NOCTTY (or having one passed to you) and then calling the TIOCSCTTY ioctl
<Keybuk> ok
<Keybuk> so
<Keybuk> terminals, controlling terminals and processes
<Keybuk> here's where this gets fun
<Keybuk> if the controlling terminal is hung up, SIGHUP is sent to the foreground process group
<Keybuk> if ^C is pressed on the controlling terminal, SIGINT is sent to the foreground process group
<Keybuk> if ^Z is pressed on the controlling terminal, SIGTSTP is sent to the foreground process group
<Keybuk> (you're getting the idea here I guess)
<Keybuk> so this is how the relationship between magic key presses and signals gets established
<Keybuk> shells care about this a lot
<Keybuk> (and yes, when you use & that becomes a background process group :p)
<Keybuk> (and when you use | they are all in the same process group)
<Keybuk> now
<Keybuk> this controlling terminal business applies to all terminals
<Keybuk> whether they be true terminals (which linux doesn't have)
<Keybuk> or virtual terminals
<Keybuk> or pseudo terminals
<Keybuk> so this is as true for your ssh login as VT1
<Keybuk> you can always access your *controlling terminal* using /dev/tty
<Keybuk> it's a badly named device node
<Keybuk> it may also be called /dev/ttyS0 or /dev/pts/4 etc.
<Keybuk> so right
<Keybuk> Linux has a bunch of virtual terminals
<Keybuk> these are the things we think of when we say "console" but we're using that wrong
<Keybuk> virtual terminals behave just like ordinary terminals
<Keybuk> they can be the controlling terminal for a process group
<Keybuk> but, unfortunately, stacked on top is the linux vt API
<Keybuk> (they didn't think to make it separate)
<Keybuk> so the stuff to set fonts
<Keybuk> to place it in raw or graphics mode
<Keybuk> to create new vts
<Keybuk> to switch vts
<Keybuk> etc.
<Keybuk> is all loaded into the tty api
<Keybuk> so, in order for X to function, it needs a VT
<Keybuk> and it needs access to that VT in interesting and familiar ways to place it into raw and graphics mode
<Keybuk> and so on
<Keybuk> it also needs to know if the *current VT* is switched
<Keybuk> so it opens the VT device it wants (/dev/tty7)
<Keybuk> and that becomes its controlling terminal
<Keybuk> so if you were to delete VT7, X would get SIGHUP :)
<Keybuk> now, on VT1-6 you have getty
<Keybuk> on VT8 you have usplash
<Keybuk> and so on
<Keybuk> this is all fine and dandy
<Keybuk> except there's this last mystical piece
<Keybuk> /dev/console
<Keybuk> /dev/console is, like /dev/tty, a fake device
<Keybuk> it points at the currently active VT
<Keybuk> whatever that is
<Keybuk> but it *behaves* like a terminal in its own right
<Keybuk> (whereas /dev/tty just behaves as a proxy for the underlying terminal)
<Keybuk> now, Upstart has a few knobs to customise the standard input, output & error file descriptors
<Keybuk> normally it just starts all jobs with them as /dev/null
<Keybuk> but for *emulation of sysvinit* it has two other options
<Keybuk> 1. set them to /dev/console
<Keybuk> 2. set them to /dev/console and issue the TIOCSCTTY ioctl()
<Keybuk> (console output, console owner)
<Keybuk> now, if your current VT is 7 (X)
<Keybuk> and you start a job that has console owner in it
<Keybuk> the new process will *take the terminal away from X*
<Keybuk> X gets SIGHUP
<Keybuk> and either hits 100% CPU or crashes

Solving this problem for good requires jobs that need user input to be rewritten:

<Keybuk> so this is clearly BAD
<Keybuk> the problem really is that things need a "console" at all
<Keybuk> jobs that require interaction should DO IT THEMSELVES
<Keybuk> they should open a VT, switch to it, and ask there
<Keybuk> or they should use usplash to do it
<Keybuk> or they should use X