[comp.os.minix] Bizarre SIGINT behavior

kevin@nuchat.UUCP (Kevin Brown) (01/06/91)

Sorry for the length of this article, but I'm describing the manifestation
of a bug in Minix in detail.  Perhaps the detailed description I provide
below will help people track this thing down.

I have been having some rather strange problems with the Minix console
driver on my system.  This problem occurs seemingly regardless of WHAT 
console driver you're using.  It occurs with Gordon Irlam's virtual
console driver running under Minix-386 (thanks, Bruce!), and it occurs 
on vintage PC-Minix 1.5.10 (floppy version, no frills).  Allow me to explain 
in the context of virtual consoles, which is where I originally thought 
the problem actually existed:

When running an application like less, which can act as the tail end of a
pipe but which takes input from the terminal, if I shell out of such an
application (thus getting me a subshell with the standard '$' prompt) and,
when the prompt is displayed, hit the INT key (usually the delete key),
all my processes for that terminal will die (and I'll be given the login
prompt).

Now, less doesn't know what terminal you're running on, and since it has
to be able to act as a member of a pipe, it will open /dev/tty as standard
input and standard output before executing the shell.  Quite reasonable,
right?

I thought that less was the cause of the problem, but it's not.  Do the
following:
	sh </dev/tty

Now hit the INT key.  Your shell and your subshell will go away, and you'll
get the login prompt back.  In fact, when I do this with the basic P-H 1.5.10
system, I get "login:" repeatedly printed on my screen until I hit <return>, 
at which point it stops and gives me the login prompt and will then accept 
a login.

I don't understand this behavior at all.  Since the virtual console driver
knows which virtual console you're on, it (supposedly) just sends a SIGINT
to the process group leader associated with the virtual terminal from which
the INT key was pressed.  At the point that you press the INT key, all the
processes associated with the terminal (including the process group leader)
are either catching SIGINT or ignoring it.  Were this not the case, you
would be able to simply do a "sh", which gives you a subshell, hit INT, and
get the same results.  This doesn't happen.

In fact, let's say that you're on virtual terminal tty4.  If you do a
"sh </dev/tty", as above, and hit the INT key, then all your processes
go away and you get the login: prompt.  HOWEVER, if you do a "sh </dev/tty4",
things work properly (note: for those of you who do not have virtual
consoles, substitute /dev/tty0 for /dev/tty4, and you'll see the same
behavior.  Works fine for /dev/tty0 but not for /dev/tty).

Aha, I thought, this means that the ACTUAL terminal has to be "opened" like
the rest.  The only place in which it is really proper to distinguish
between devices is in fs/device.c, right?  So I went there and implemented
code that would, if it saw that /dev/tty was being opened, fix up the
message and pass it on such that the actual control terminal would be 
opened.  Since doing a "sh </dev/ttyN" works, I figured that this was the
problem.  I was wrong.  If it's related to the actual inode of the device
that's being opened, then I can't immediately conceive of an elegant
solution to the problem.  I don't much like the idea, nor can I conceive
of a reasonable way, of putting in code to fetch the inode of the REAL
terminal that's being referenced when /dev/tty is being opened.

Other symptoms: if you're running a virtual console system, or have an
external terminal attached (I don't know if you get this behavior from
an external terminal, but my money says you will), you can log into the
console (or a virtual console), do the "sh </dev/tty", and then send
signals to the processes on the console you logged into from your other
session.  Let's say that the original shell process that's attached to
the console is process 41, and the subshell (which is taking its
input from /dev/tty) is process 42.  If you do a "kill 41", nothing
happens (kill without a switch, e.g. -9, sends a SIGINT to the specified
process), regardless of where you do it from.  If you do a "kill 42"
from the terminal in which you're running the subshell, nothing happens
(which is the way it should be).  HOWEVER, if you do a "kill 42" from
the OTHER terminal, all the processes for the console go away and you
get a login prompt on the console.

In other words, if you do a "sh </dev/tty", then try to SIGINT the subshell
process WHILE IT'S WAITING ON A PROCESS, then there's no effect (which is
the right behavior).  But if you SIGINT the subshell process (either via 
the INT key or via a kill command) when it's waiting for input, it and all its
parents will die.  SIGINTing the parent of the subshell does nothing (which
is the way it should be).

Help!  I don't understand at all what the @#$@#!! is going on here.  It's
almost as if doing a "sh </dev/tty" blows away the signal masks of all
the processes associated with the control terminal, but there's no code in
there that's actually doing any such thing that I've seen.  And why would
doing "sh </dev/tty" result in the above behavior while doing "sh </dev/tty0"
won't?  I'm baffled...:-(

The problem happens regardless of which version of init or anything else
I'm running.  It happens with both 16 and 32 bit versions.  It happens with
Minix 1.5.10 as distributed by PH.  Whatever it is, it's caused by code
that's common to all these different flavors of 1.5.10.  Can the Atari
people speak up and tell us if ST-Minix behaves the same way?

Has anyone else experienced these problems?  Has anyone else found a fix?
It's not a devastating problem, mind you (if you run a program from the
subshell with input from /dev/tty, and hit INT while running it, everything 
works fine.  I'm SOOOO confused!), but it's quite annoying.  I don't know
about you, but I *don't* like weird behavior like this in my operating 
system.  :-(

It could be worse.  I *could* be having hard drive problems...:-)

Thanks in advance.


--
			Kevin Brown
		Addresses in preferred order:
		    csci31f7@cl.uh.edu 
		nuchat!kevin@uunet.uu.net

HBO043%DJUKFA11.BITNET@cunyvm.cuny.edu (Christoph van Wuellen) (01/07/91)

I remember that I have seen parts of that strange behaviour on my 68K
MINIX-1.5 system (especially repeated login: prompts after hitting the DEL
key).
C.v.W.

joerg@mwtech.UUCP (Joerg Werner) (01/12/91)

In article <1991Jan6.042939.10130@menudo.uh.edu> uace0@menudo.uh.edu.UUCP
 (ATARI Computer Enthusiasts) writes:

>I thought that less was the cause of the problem, but it's not.  Do the
>following:
>	sh </dev/tty
>
>Now hit the INT key.  Your shell and your subshell will go away, and you'll
>get the login prompt back.  In fact, when I do this with the basic P-H 1.5.10
>system, I get "login:" repeatedly printed on my screen until I hit <return>, 
>at which point it stops and gives me the login prompt and will then accept 
>a login.

I have a similar problem, maybe the same:-).  It occurs if /etc/rc
executes the following program:

#include <signal.h>
trap() {exit(1);}
main()
{
	char buf[256];

	signal(SIGALRM,trap);
	alarm(5);
	printf("Hit <Return> or wait 5 seconds.\n");
	read(0,buf,sizeof(buf));
	exit(0);
}

If I wait and the alarm signal occurs, the login prompt is printed
repeatedly and no login is accepted.

>Aha, I thought, this means that the ACTUAL terminal has to be "opened" like
>the rest.  The only place in which it is really proper to distinguish
>between devices is in fs/device.c, right?  So I went there and implemented
>code that would, if it saw that /dev/tty was being opened, fix up the
>message and pass it on such that the actual control terminal would be 
>opened.  Since doing a "sh </dev/ttyN" works, I figured that this was the
>problem.  I was wrong.  If it's related to the actual inode of the device

The problem lies indeed in fs/device.c. More specifically rw_dev2() is the
hog. The global pointer `fp' points to the callers process table [Minix
Manual, line 16266]. If the caller is a user process everything works fine.
But sometimes MM calls the FS, and `fp' points to MM's process table, of
course. That's the case if a signal is sent to a process. If the process
is hanging on a system call (READ for example) the FS must be informed.

But what happens if rw_dev2() is called now? The controlling tty of the MM
is checked:-((

This means that fp->fs_tty is always 0, and the message is sent to the MEM
task. A hanging read-call is  n o t  terminated!!!

Luckily there is a easy way to find out which process table we need. The
message contains the process number! Please have a look at the patch. I
hope this helps (and if, please let me know).

Ciao Joerg

PS: I'm using MINIX ST 1.5.[10.3].
    BTW, the result of two days work, was a 2 line patch :-)
------------------------ cut here -------------------------------
*** /usr/src.1.5.10.3/fs/device.c	Tue Nov 20 21:19:33 1990
--- /usr/src/fs/device.c	Thu Dec 27 16:26:58 1990
***************
*** 188,193 ****
--- 188,196 ----
   */
  
    int task_nr, major_device;
+   register struct fproc *fp;
+ 
+   fp = &fproc[ mess_ptr->PROC_NR ];
  
    if (fp->fs_tty == 0) {
  	mess_ptr->DEVICE = NULL_DEV;
------------------------ cut here -------------------------------
-- 
Joerg Werner, email: joerg@mwtech.UUCP, voice: 49-(0)6151-37 33 66