Ctrl-C without process groups

Ive implemented a shell on Uniflex. Uniflex does not have process groups - which I think is the problem - because when I type Ctrl-C, the SIGINT is delivered to the shell only. If its running a command, I explicitly forward the SIGINT to the running command. It works fine but can’t help feeling I’m “Doing it Wrong”.

Is there a cleaner way?

I just poked at Advanced Programming in the Unix Environment, and while I suspect it addresses this somewhere, I didn’t see it in a few moments of perusal.

What happens if you just ignore SIGINT in the shell, does the process receive it? I think it should likely go to all processes that have the terminal open for input, at least in the absence of process groups.

In the early kernel source (v6) that I have a copy of, the tty driver sends SIGINT (usually from ^C) or SIGQUIT (usually from ^\) to every process that has the matching tty as its control terminal. I mean it literally loops through the entire process table and just blindly signals every process with matching tty. It’s that simple.

So I agree with @elb’s last sentence. Even though Uniflex probably came from a later version of Unix (e.g. v7 versus v6), this is pretty basic and wouldn’t change. So I keep thinking maybe your shell isn’t setting the control terminal for child processes…except that I also think this happens by default. You only have to take action if you want the child process to not inherit the shell’s control terminal.

So, I got nuthin’. Hmmm.

1 Like

So sending to every process on a tty - does that not kill the shell itself also?

Ill check with Ghidra . Cheers

It does. The shell normally traps SIGINT.

The shell ignores SIGQUIT and handles SIGINT by sort of going “back to the top” and prompting again. If it helps, I put the source code for the Unix v7 Bourne shell here. Some of the relevant code is in fault.c.

The source code was already online, but in a much clumsier form. The licensing situation is unclear. Most likely nobody will care.

As you may know, the code is all written with preprocessor macros that make it look like ALGOL68. The macros are in mac.h. It wouldn’t be difficult to reverse them. More work would be required to make the code compile with a modern compiler.

2 Likes

So I removed my forwarding SIGINT to the child process in my shell.

And running from the console it behaves as you describe - eg I can interrupt sleep sub command by typing Ctrl-C

See video: https://youtu.be/Qul0gaq7eZs

When I run my window manager, my shell is on the end of the pseudo-terminal, and without the forwarding of the SIGINT, sub commands cannot be stopped with Ctrl-C. They dont get SIGINT.

Whats weird is I found the code in the OS handling of pty and it does exactly as you described of running through the entire task list looking for a tty and sending a SIGINT to each…

Perhaps I’ve not setup the pty right - they are kinda funky on this system.

Code if anyone is interested: tek4404/wmgr/wmgr.c at main · Elektraglide/tek4404 · GitHub

When I run my window manager, my shell is on the end of the pseudo-terminal, and without the forwarding of the SIGINT, sub commands cannot be stopped with Ctrl-C. They dont get SIGINT.

Whats weird is I found the code in the OS handling of pty and it does exactly as you described of running through the entire task list looking for a tty and sending a SIGINT to each…

Ouch. That sounds … wrong, and I don’t have any explanation for it. The ancient Unix code that I have access to doesn’t have anything in it that even slightly resembles ptys.

Wikipedia says ptys had already been invented (for other operating systems) and were added in (what today we would call …) forks of v6, for example at BBN. I found this link to a very early pty implementation.

Note that the URL path has .../dmr/... in it; version 6 was supplied in two directories, called ken and dmr.

None of this goes very far toward solving the issue you’re seeing, I’m afraid.

1 Like

I would have naively expected that the shell would get the input from the terminal and - because it’s a shell - sent a signal to the appropriate child process(es). But that mostly shows that I don’t know the internals of Unix. I very nearly went to my handy Tanenbaum to see what Minix does… but I didn’t.

1 Like

Right, and the Uniflex shell does just that. There must be a reason for doing so.

(fyi, I use “_possibly” when reverse engineering in Ghidra - kill_subtasks() does do what it says it does)

1 Like