[net.unix-wizards] 4.2 BSD Signals: A Proposal

cak@Purdue.ARPA (01/12/84)

From:  Christopher A Kent <cak@Purdue.ARPA>

I think it's wonderful from a purely pragmatic standpoint. I probably
won't write any new code that uses it (I'm a true believer), but we
have so much old code that uses it that things have been a real pain
around here trying to convert it all and leave it portable (one program
system in particular, which we distribute, needs to be able to run on
4.1 and 4.2 and has to do timeouts of reads).

By leaving the default behaviour as restartable system calls, "new"
programmers will be encouraged to use that model, especially if they
have only read as much as they need to know and haven't seen the manual
page for sigrestartable yet.

I think it's a win all around.

Cheers,
chris
----------

mike%rice@sri-unix.UUCP (01/12/84)

From:  Mike Caplinger <mike@rice>

[This message has a possibly worthwhile suggestion at the bottom.
Readers interested in skipping the rest can feel free to do so.
- Mike Caplinger]

First, as I understand them 4.2 restarting is exactly like 4.1 restarting
after a new signal feature has been used.  This is already a compatibility
problem.  Most 4.1 programs I've written have used the new interface.

I'm really scared of making any changes to 4.2 that don't make it into
ALL the distribution tapes that are going to be sent out.  I like
Mike's solution, but do you really think it's worthwhile trying to do
such things in the name of portability?  I believe the following
things:

1) There will be many 4.2 programs that will never run under Sys V.
2) There will be many Sys V programs that will never run under 4.2.
3) Most educational sites will never run Sys V on VAXen.  We would only
   run Sys V on any machine if we were stuck with it.

Experience with the millions of local hacks that ran around under v7,
and trying to cope with /usr/group and Usenix software that used them,
has made me very wary of local hacks.  I suspect there will always be
purists who refuse to implement local hacks; I even think I'm one of
them.

I wonder if, now that rumors say Berkeley isn't really doing
development work, we might get people there to listen to improvements
like yours.  How about Ultrix?  Will DEC listen?

Also, it has always bothered me that the terminal driver in 4.1 made it
necessary to do as many as 4 ioctls in order to do logically-connected
things.  That was a compatibility move too...  Of course, this change
doesn't using the new semantics clumsy.

I guess what I would like is for the change to be added, but controlled
by the COMPAT #ifdef.  Good luck lobbying for it!

		- Mike

ps.  If signal() was kept as a COMPAT system call, and a front-end was
written to go in a special library (liboldsig?) then use of that system call
(as opposed to the signal(3) library call) could detect whether new or old
behavior was wanted, obviating the sigrestartable syscall, just as 4.1
detected the use of a new feature and set SOUSIG accordingly.  I think...

gwyn%brl-vld@sri-unix.UUCP (01/12/84)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

I think perhaps you are attempting to bundle too many things together
that should be orthogonally selectable.  I would much prefer that the
state of the u_eosys flag bit RESTARTSYS be available to the signal
handler and that there be a way to turn off this bit before resuming
after the signal handler.  As with your proposal, any program not
using this added feature would obtain the distributed 4.2BSD
behavior.  This addition would permit the machine dependencies to
be removed from the signal(2) emulation that I previously posted,
so that "old style" UNIX signal behavior would be available simply
by using the signal() library routine, with no extra BSD-specific
kludge calls needed in user source code.

guy@rlgvax.UUCP (Guy Harris) (01/14/84)

	First, as I understand them 4.2 restarting is exactly like 4.1
	restarting after a new signal feature has been used.  This is
	already a compatibility problem.  Most 4.1 programs I've written
	have used the new interface.

I believe this is correct; the "vnews" we ran on 4.1 used the new signal
mechanism so that it could be suspended, and it turned out that typing
one's interrupt character didn't work like it was supposed to because the
read didn't get EINTR, so I had to stick in a (surprise, surprise) "setjmp"/
"longjmp" pair.

	Also, it has always bothered me that the terminal driver in 4.1 made it
	necessary to do as many as 4 ioctls in order to do logically-connected
	things.  That was a compatibility move too...  Of course, this change
	doesn't using the new semantics clumsy.

This was actually somewhat inherited from V7; the System III/System V handler
cleans this up, although if 4.3BSD or whatever picked up the USG tty driver
and then re-Berkeleyized it they might have to introduce a second "ioctl" to
turn on the local flags and supply the local control characters, which would
bring us back to where we started from...

	ps.  If signal() was kept as a COMPAT system call, and a front-end was
	written to go in a special library (liboldsig?) then use of that system
	call (as opposed to the signal(3) library call) could detect whether new
	or old behavior was wanted, obviating the sigrestartable syscall, just
	as 4.1 detected the use of a new feature and set SOUSIG accordingly.
	I think...

"signal()" is already kept around in 4.2 as part of the 4.1 binary compatibility
feature, and if you issue the "old signal" system call it does, indeed, set
SOUSIG (in fact, that's the *only* place SOUSIG gets set), so your suggestion
has already been implemented in vanilla 4.2BSD if you define COMPAT when you
build your system.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

tjt@kobold.UUCP (01/15/84)

Actually, this is a follow-on to:

	    Also, it has always bothered me that the terminal driver in 4.1 made it
	    necessary to do as many as 4 ioctls in order to do logically-connected
	    things.  That was a compatibility move too...  Of course, this change
	    doesn't using the new semantics clumsy.
    
    This was actually somewhat inherited from V7; the System III/System V handler
    cleans this up, although if 4.3BSD or whatever picked up the USG tty driver
    and then re-Berkeleyized it they might have to introduce a second "ioctl" to
    turn on the local flags and supply the local control characters, which would
    bring us back to where we started from...

If you "re-Berkeleyize" the USG tty driver, any additional ioctl should
work in the spirit of the USG ioctl's, and let you set *all* the flag
words/special characters with a single ioctl.  I thought part of the
reason for all them ioctl's in the 4BSD tty driver (actually from
IIASA) was leftover from V6 days when the stty/gtty entry point was
passed *exactly* three int's (or six char's) from user space, and this
was carried over as a superstition.
-- 
	Tom Teixeira,  Massachusetts Computer Corporation.  Westford MA
	...!{ihnp4,harpo,decvax}!masscomp!tjt   (617) 692-6200 x275

mike%brl-vgr@sri-unix.UUCP (01/18/84)

From:      Mike Muuss <mike@brl-vgr>

REFRESHER.

On 4.1 and earlier UNIX systems, signal handlers had several attributes:

*)  After a signal was caught, the handler was reset to SIG_DFL.

*)  If the process was executing a (kernel) sleep() at "low" priority,
    and a signal was processed, the system call would abort, returning
    an error code (-1), with errno = u.u_error = EINTR (interupted
    system call).

On 4.2 BSD UNIX, these two aspects of signal handling were altered
(along with some other, nice improvements, which are not germane).

1)  The signal handler remains "installed" until explicitly changed.

2)  System calls which may (kernel) sleep() at "low" priority will
    be silently restarted after processing an incomming signal.
    The signal handler will have no idea if this is happening or not.

PROBLEM.

Clearly, programs written for the old style signal interface will have
a fair amount of difficulty coping with difference #2 above, if they
depend on signals (especially timer signals) interrupting a system
call.  Network software which wishes to run timouts around network
reads will have to longjmp() in the signal handler, rather than
being able to depend on just returning, with an EINTR to be returned
from the read/write sys-call that timed out.  Editors and shells
will have to expect their I/O to be restarted after SIGINT, etc.
(You would not believe the crud that Berkeley had to do to /bin/sh
to make it still capable of re-printing $PS1 after a SIGINT (^C, etc).).

Certainly, change #1 is "mostly harmless";  the number of programs
which will break is minimal -- the timing windows which this change
fixes were something that no mortal programmer would dare depend on.

However, change #2 is truely problematic:  Certainly, there are advantages
to the new style signal interface, and programs which are written with
this style of operation in mind should work out well.  However, no matter
how hard we try, few of us will be able to afford the luxury of running
4.2 BSD on *all* our machines.  Those of you planning on purchasing
a Cray-2 (as we are), will have to contend with System-V UNIX (at least
to start with).  Many other vendors will be non-4.2 BSD, and it is too
late to stomp them all out (pitty, no?).  And somehow, those venerable
old PDP-11s just keep on refusing to quit!

THEREFORE, the problem of program portability rears it's ugly head.
4.2 people (true believers) will, of course, deisre to import quality
software from elsewhere ("expensive, yes, extravagant, no"), without
having to re-write all the signal code.  Others may wish to be able
to use 4.2 code on their own system ("rotsa-ruck").  Being in the
former camp, I would like to offer the following solution:

PROPOSED SOLUTION.

In proc.h, SOUSIG (1 bit in p_flag) is defined to mean "this process is using
the old signal mechanism".  This piece of information is used in two ways:

1)  To determine resetting of default signal handling after traps
	(in sys/kern_sig.c and sys/kern_xxx.c).

2)  To determine restartability of interrupted ("slow") system calls
	(in kern_exit.c, sys_generic.c, sys_inode.c).

By adding another bit to the p_flag word called SDFLSIG and assigning
it function #1 (above) to this new bit, and then redefining the meaning
of SOUSIG to JUST function #2 (above), +and+ by adding a new sys-call
(#151, sigrestartable()) which permits the user to manipulate the
state of the SOUSIG bit, then a solution can be achieved.

For programs which do not use the new sys-call, standard 4.2 functionality
occurs.

Programs which wish to avoid having their sys-calls restarted may say:

	sigrestartable( 0 );

and get the 4.2 interface, with continuously installed signal handlers,
but with sys-calls returning the old familiar EINTR.

Calling sigrestartable() with a non-zero argument restores the 4.2 BSD
style restartable sys-calls, so that one can "live in both worlds"
by switching back and forth.  The sys-call is as fast as getpid(),
so pairs could reasonably be used around old-fashioned code if one
desires to "blend" signaling style within a single program.

STATUS.

This evening, I installed the change I proposed above, into 2 of our 780s.
Effort to change:
	h/proc.h		2 lines
	sys/init_sysent.c:	1 line
	sys/syscalls.c:		1 line
	sys/kern_sig.c		14 lines
	sys/kern_exec.c		1 line
	sys/kern_fork.c		1 line
	sys/kern_xxx.c		1 line

To the best of my ability to test it, this new system call operates
exactly as I have described above.

QUESTION.

What does the UNIX-community-at-large think of this strategy?
If people feel that this is a reasonable solution to the 4.2 signal
"problem", DPK and I will arrange to reproduce many copies of a
1-page document describing how to install this code into your 4.2
kernel, and distribute them at UNIFORvM in Washington DC next week.

On the other hand, if a better proposal can be brought forth,
I am willing to withdraw this proposal and implement something
else, assuming that it offers a solution of similar generality,
elegance, and simplicity (pardon the self-admiration).

CREDIT.

The motivation for addressing this problem at this time came from
a program which Doug Kingston has been working on.  His struggles,
his requests, and his constructive feedback were instrumental in
shaping the form of this solution.  Together we evaluated 7 or 8
different solutions to this problem, before the present solution
was arrived at.

COMMENTS.

Please mail your responses to this issue back to the full list.
This issue is too important to discuss privately.

	Best,
	 -Mike Muuss

SOURCE CODE.

Just in case you desire to try this change yourself, here is the code:

h/proc.h (2 changes):

change comment to:
#define	SOUSIG	0x0100000	/* old signal semantics: no restart (BRL) */

add at the bottom:
#define SDFLSIG	0x2000000	/* reset signals to default handling (BRL) */


sys/init_sysent.c (2 lines from the bottom):

	1, sigrestartable,		/* 151 = sigrestartable (BRL) */

sys/syscalls.c (1 line from the bottom):

	"sigrestartable",	/* 151 = sigrestartable */

sys/kern_xxx.c (3 lines from the bottom):

from:
	p->p_flag |= SOUSIG;
to:
	p->p_flag |= SOUSIG|SDFLSIG;

sys/kern_exec.c (80% into the file):

from:
	u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
to:
	u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG|SDFLSIG);

sys/kern_fork.c (50% into the file):

from:
	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG));
to:
	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG|SDFLSIG));

sys/kern_sig.c (in psig(), 85% into the file):

from:
		if (p->p_flag & SOUSIG) {
to:
		if (p->p_flag & SDFLSIG) {

and, after
#define	cantmask	(mask(SIGKILL)|mask(SIGCONT)|mask(SIGSTOP))
near the front of the file, add this routine:

sigrestartable()				/* BRL-specific */
{
	register struct a {
		int	restartable;
	} *uap = (struct a *)u.u_ap;

	/* BRL syscall to permit non-restartable signal behavior */
	if( uap->restartable )
		u.u_procp->p_flag &= ~SOUSIG;	/* Restartable */
	else
		u.u_procp->p_flag |= SOUSIG;	/* Non-restartable */
}

HAPPY HACKING!

guy@rlgvax.UUCP (Guy Harris) (01/22/84)

> If you "re-Berkeleyize" the USG tty driver, any additional ioctl should
> work in the spirit of the USG ioctl's, and let you set *all* the flag
> words/special characters with a single ioctl.  I thought part of the
> reason for all them ioctl's in the 4BSD tty driver (actually from
> IIASA) was leftover from V6 days when the stty/gtty entry point was
> passed *exactly* three int's (or six char's) from user space, and this
> was carried over as a superstition.

The multiple "ioctl"s to set the terminal modes in 4BSD comes from V7, where
they also had multiple "ioctl"s.  I suspect the reason was that the V7 driver
was done, it was done by adding stuff to the V6 driver which did have to
use only what the "stty/gtty" routines could handle, so instead of redoing the
"ioctl" interface entirely they added new "ioctl"s, and Berkeley continued
the tradition for compatibility (i.e., "stty/gtty" and the old "ioctl"s still
worked).  The people who did the 3.0 driver probably decided that, instead of
taking the V6-like 2.0 driver and adding all the V7 "ioctl"s, they'd redo the
whole thing right.  In 4.1cBSD there was sort of a half-assed attempt at
redoing the "ioctl"s - they added an "ioctl" to set the "sg_flags" and local
flags words as one "long", and an "ioctl" to set all the special characters,
but one still had to use the old "ioctl" to get/set the speeds - but that was
backed out in 4.2BSD.

My only concerns about extending TCGETA/TCSETA to include more special
characters and flag bits would be:

1) Adding the flag bits to existing words might conflict with future extensions
from Bell; adding a new word would be safe but slightly ugly (for instance, the
"echo control characters as ^x" bit belongs in c_lflag but Bell may eventually
use all 16 bits of that "short").

2) Programs which do a TCSETA without first doing a TCGETA on the standard
input/output/error deserve to break (the *only* right way to set the modes
on a port whose modes have already been initialized is to read the current
modes, change the "termio" structure, and set the modes), but some programs
which do the first open on a line and set the modes directly (communication
programs, for instance) might break because they set the new mode bits and
control characters to zero without realizing that this may have an undesired
effect.  By and large, setting the bits to zero would be harmless, as leaving
those bits off leaves the driver behaving like the standard USG tty driver,
but setting the control characters to zero doesn't disable them.  The latter
is actually a misfeature of the driver to some degree; for example, "getty"
under System III sets your "break" or "eol" character (V7 calls it the "break"
character and USG UNIX calls it the "eol" character) to NUL (zero) rather than
'\377'.  The latter was guaranteed to disable the control character in V7,
as the character was masked down to 7 bits before it was compared against the
special characters, but may not do so in USG UNIX as the stripping of the
eighth bit is an option which can be set independently of most other options
(this is useful, for instance, if you have a terminal with a META key which
turns the eighth bit on; you can use the META key without all the disadvantages,
like disabling XON/XOFF, of the V7 "raw" mode).  The UNIX 2.0 backward
compatibility "ioctl" TIOCSETP (which several people may have made backward
compatible with V7 instead) sets the EOL (and the S5 EOL2) characters to
0, also.

I would vote for changing the USG driver to consider NUL not to ever be the
erase, kill, interrupt, quit, EOF, EOL, EOL2, etc. character, so that
setting that character in the "termio" structure to NUL would be the official
way to disable them.  This would mean that most (if not all) programs which
initialized a terminal port would not enable those characters if what the
program did was fill in a structure and do a TCSETA without first doing a
TCGETA.  Under these circumstances, changing the shape of "struct termio"
would only break binary images of programs, and if that was really a problem
TCSETA, etc. could be given different "ioctl" numbers and the old ones could
be left around for backwards compatibility.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy