14

Within modern shells, I am able to leave a process via one of two control sequences:

  1. Usually Ctrl+C will directly send SIGINT to the majority of shell commands (e.g. ping, echo, cat)
  2. A few processes capture the terminal and prevent that from working, but Ctrl+Z will still suspend them (e.g. vi, man, albeit not screen) and then I can kill %1 to finish them off or fg if I do want to resume later.

Both of these work from the very terminal running the process. That is, I can use them without needing a second login session in another window/tab.

However, I am in the middle of trying to set up a second serial port in older versions of Unix (e.g. Unix V6 or 2.11BSD) running in an emulator, and keep hitting situations where I run e.g.

echo "test" > /dev/tty00

That command works fine for /dev/tty but /dev/tty00 is apparently still not configured right on my part. And so the command just hangs! At this point, I can't do anything to stop it from trying/waiting. It doesn't seem to ever time out. Is there some more arcane key sequence or other strategy for resolving a Unix process that's stuck like this, when only one terminal is available?

(I noticed this on a real PDP-11 at Living Computer Museum as well, where nothing I knew to type on the ASR-33 terminal seemed to be able to interrupt certain commands after I ran them.)

UPDATE: thanks for all the tips below! I can now note that it is possible to kill the process by PID if I do have a second terminal open, i.e. it's not in what we would nowadays see as the dreaded uninterruptible sleep state. However so far none of the key combinations below have worked, at least not as entered via the TELCOM program on a Tandy Model 102 (which I understand may complicate things as far as how keypresses get sent and I'll have to test separately).

9
  • 1
    Isn't that more like a question for Unix.SE ?
    – Raffzahn
    Dec 16, 2019 at 19:41
  • 6
    @Raffzahn Maybe, but I'm not sure 1970s versions of Unix are in scope for that site? As my question includes, I know how to do this generally on "Unix & Linux" but it doesn't seem to work in retro versions and/or on retro terminals.
    – natevw
    Dec 16, 2019 at 19:44
  • Sure, but then again, it's safe to assume that a site specifically dedicated to a single system might concentrate way more knowledge than a generic place like here. Isn't it?
    – Raffzahn
    Dec 16, 2019 at 19:47
  • 2
    You can try sending a break signal over the terminal, as this works in some cases where CTRL-C doesn't, but I don't know how you would do this on your terminal. Note that a break isn't a normal character, there's no ASCII code or escape sequence for it. It's the result holding the serial line at logic level 0 for more than the length of a character.
    – user722
    Dec 16, 2019 at 20:22
  • 1

6 Answers 6

14

Yes, you should be able to interrupt a running process using the interrupt key.

In Unix v6, the default interrupt key (intr) is ^?, aka DELETE, aka RUBOUT (ASCII 127). Also, the default character-erase key (erase) is #, and the default line-erase key (kill) is @. You can use stty to change the 'erase' and 'kill' keys but v6 stty doesn't let you change the 'intr' key without changing the kernel (as far as I know).

In 2.11BSD, I think the kernel defaults are still the same as in v6 (at least, using the old terminal driver), but the command "stty dec" will switch to the more common intr=^C, erase=^? and kill=^U all in a single step. I would have to set up a 2.11BSD system and test this to be sure.

^Z is a 'job control' key and wouldn't be available in Unix v6 at all. In 2.11BSD it would only be available if you are using csh and the new terminal driver that supports jobs (2.11BSD included both an 'old' terminal driver inherited from Unix v7, as well as a 'new' BSD terminal driver that included a number of new features including process groups, used to support jobs).

4
  • The erase/kill part of the answer, though interesting, is not really relevant to the question. Dec 17, 2019 at 0:13
  • 7
    It's relevant to the answer: it sets the context that the signal keys are part of the terminal configuration just like the edit keys are, and reinforces the idea that the defaults are not what you would expect them to be. Also, I suspect that many people who don't know the default interrupt key also won't know the default editing keys, making the answer more useful to others.
    – Ken Gober
    Dec 17, 2019 at 6:57
  • I agree it was a bit off-topic, but also agree that explaining erase/kill was useful :-) Been struggling when my terminal sends a backspace, it looks like I have fixed a typo but only in the local echo-ed back display. But the command fails cryptically. (E.g. ll backspace s looks like two characters ls but seems to get interpreted as all four characters.) With # and @ it's just the opposite! Leaving the stty defaults, ll#s is echoed back as shown, but gets interpreted as ls! And rm -rf /@ gets ignored as a blank line [maybe don't try that exact line at home though].
    – natevw
    Dec 24, 2019 at 4:49
  • That “cryptic” behavior is the result of a disconnect between the terminal and the terminal driver configured using stty: the terminal and the driver must both interpret the control codes the same, to stay in sync. With default settings the driver uses # and @, but the terminal doesn’t so you see those characters - what you see is not what the driver sees. Otherwise, you use the keys the terminal knows how to interpret, but now the driver knows nothing about them. Fix: disable local echo in the terminal, enable remote echo in the driver, and fix the stty settings to match the terminal ;) Nov 30, 2020 at 19:21
6

The 'quit' signal, though not yet called a signal, was apparently implemented in the kernel and tty driver by 1971 -- see this Unix manual, which I think must be the 1st edition, since there's also a 2nd edition manual at bitsavers, with a later date.

Look for the 'sys quit' page, which as ever, is to be found in section II.

To send a 'quit', type ctrl-\ on the tty.

It was possible for the program to handle or ignore a quit signal, but the manual warns against it, so perhaps your hung program can get unhung.

I don't know the answer to whether a quit can be delivered to a program waiting in a syscall. I would assume the answer is in general that it could be, although if the process is hung on I/O, and this is still the "need to swap out to context switch" days, that might pose a difficulty.

4

Ctrl-C, and other similar mechanisms rely on software at the receiving end reading the character, interpreting its meaning, and then sending a signal to the appropriate process. The problem with this is that if the receiving program is hung, there is a long queue of characters ahead of the ctrl-c character waiting to be processed, or there is some other kind of deadlock in the terminal's output stream, the interrupt might never happen.

"Dumb" terminals were connected to computers (or their front-end processors) via RS-232 - Wikipedia standard cables, with separate wires for request-to-send, ready-to-receive, receive-data, etc.

When a process hung, or if one simply wanted to interrupt it, the keyboard provided a "Break" key. Unlike the other keys, this key didn't add a character onto the output stream. Instead, it dropped the electrical signal on the transmit-data line (for perhaps a quarter second). The hardware at the receiving end would notice this drop, and the hardware would notify the OS, which would send a SIGINT signal to the process that was attached to the terminal.

This method avoids most software and bypasses the normal data stream, so it was almost instantaneous and almost always successful.

2
  • This could be a good tip for some systems! My serial control app allows me to send a "Break" via its menu or ⌘B which I'm guessing is this. In my case however [with a USB-serial converter to a software-simulated serial terminal], it only echoes back random-ish garbage when I try it. It does not appear that e.g. Unix V6 supported this either but maybe some earlier/later versions on other platforms did.
    – natevw
    Dec 24, 2019 at 4:57
  • Many USB-to-serial converters doesn't know that to do with a break character. They even lacks the ability to drop the line the same way an old terminal would have done it. Dec 26, 2019 at 19:13
3

It may be difficult to get signals to a process that's blocked on a syscall. It's possible that some early UNIXes don't know how to interrupt a syscall on receipt of a signal. In these cases you may just have to find some way to unblock the I/O device before the process blocked on it will terminate.

However, you should be able to send a signal to any process by first determining its PID with eg. ps awx | grep echo, and then issue kill -9 <pid>. Both of these will need to run on an unblocked terminal, of course.

5
  • Thanks, I've actually been reading the Lions book but don't have my paper copy with me right now. Starting with the helpful assumption that it's stuck in a syscall might help find an answer to the single blocked terminal problem. (In my case this is a PiDP-11 so I might be able to use the "debugger" panel to intervene too.)
    – natevw
    Dec 16, 2019 at 19:57
  • Yah, BSD and System V took different approaches to how signals could interrupt blocking system calls, so there's probably some common ancestor that didn't handle this at all.
    – user722
    Dec 16, 2019 at 20:26
  • 1
    If a process is stuck in an uninterruptible device syscall, even kill -9 might not break it out. I remember having this problem decades ago when trying to access a hung tape drive.
    – Barmar
    Dec 17, 2019 at 18:03
  • @Barmar Correct, that's why I drew a distinction between sending a signal and having it take effect. The special thing about SIGKILL (-9) is that (unlike SIGINT or SIGTERM) it can never be ignored or handled by the receiving process, so only relies on the kernel to act properly.
    – Chromatix
    Dec 17, 2019 at 18:09
  • It seems likely that whatever caused the problem in the question is just such an interruptible state, since I don't think the shell itself blocks the signal.
    – Barmar
    Dec 17, 2019 at 18:11
1

In the case of Version 6 Unix, the stty shell command does not appear to allow configuration of the interrupt or quit sequences except to disable them completely via the raw mode. In the stty function documentation, it mentions the hardcoded characters almost in passing regarding raw mode where:

[…] the interrupt character (DEL) and the quit character (FS) are not treated specially [in raw mode].

(UPDATE: this is documented in even better detail within the TTY(IV) manpage.)

In my testing I found, using a command like sleep 100:

  1. Pressing Ctrl-C has no effect.
  2. Pressing delete, configured in my terminal emulator to send DEL (instead of BS) returns control to the shell silently
  3. Pressing Ctrl-\ returns to the shell, logging "Quit -- Core dumped"

So split between another-dave and Ken Gober's replies are the only two answers for this particular version of Unix. Specifically, most processes would be interrupted with DEL ("delete", ASCII 127) and can be quit with FS ("file separator", ASCII 28).

I still have not found a way to exit my original echo "test" > /dev/tty2 style commands when they hang, except via kill from another terminal. Which seems a bit strange to me, but is probably out of scope for my question here.

0

This isn't strictly an answer but might help you to discover one.

When at a command prompt, enter the command "stty -a". This should result in a listing of the key bindings for sending various signal types from the terminal to the currently running process. This might help in finding an answer.

Some programs (as you've noted) do change the terminal mode and can disable at least some of the bindings when running. I remember (years ago) needing to kill programs and then type "stty sane" to get the terminal mode back to a reasonable state for the shell.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .