[comp.unix.wizards] Universal OS

guy@gorodish.Sun.COM (Guy Harris) (04/26/88)

> 	3. OS - what is the interface to the signal handler under
> 		SYS V and BSD!

This particular point really continues a discussion started in comp.lang.c.
The discussion was inspired by some misconceptions about UNIX signal handlers.

Any rational version of UNIX will permit signal handlers to take a single
argument that is the signal number.  Any version that obliges signal handlers
to be written to take more than one argument will cause *so* much
already-written code to break that it can fairly well considered to be broken
itself.

Fortunately, 4BSD has, as far as I know, only been implemented only on systems
where the extra "signal code" argument that it passes doesn't make a
difference.  As such, it is not (yet) broken in that sense.

ANSI C specifies that signal handlers take one and only one argument.  This
also happens to break existing code; however, assuming that there are machines
that cannot support "varargs" without "varargs" functions being explicitly
declared as such, they had no choice.

In other words, if you want to write portable code, write it so that signal
handlers take one argument.  This will work on any non-broken UNIX system.
Thus, the issue of the interface to the signal handler is not an issue raised
by multiple versions of UNIX.  It *is* an issue if you have non-UNIX systems,
but if you have to deal with non-UNIX systems, it's probably one of the least
of the issues you will have to deal with.

As for the relevance of this point to "most people" and "most users", the
people mentioned in the original article:  to borrow a phrase I have heard
attributed to Frank Zappa, "most people" or "most users" wouldn't know a signal
handler if it came up and bit them in the ass.

shankar@hpclscu.HP.COM (Shankar Unni) (04/27/88)

> In other words, if you want to write portable code, write it so that signal
> handlers take one argument.  This will work on any non-broken UNIX system.

I presume that by broken UNIX systems, you mean "most" UNIX system. What am I
going to do with that ubiquitous "SIGFPE"? That could mean the most amazing 
number of vastly different things on most systems. This becomes an especial
problem if you have funky architectures that catch you on many funnies in many
languages. As an example, take range-checking in Pascal (shudder! :-)). We'd
like to avoid the overhead of generating 4 or 5 instructions to check a value
and call a routine if anything goes wrong. Instead, we'd like to just use
a "compare and trap" instruction. *Of course*, the trap raised by this
instruction *just happens* to be the same one that's raised by an Integer
Overflow or a divide by zero (even the subcode). We thus have to do some
pretty fancy decoding of the instruction which trapped to figure out what
happened. That could have been done by the UX signal mechanism instead, saving
us a lot of grief...

Since machines have come a *long* way since the xxx-7, maybe it's time to
define a consistent and meaningful convention (standard?) for such signals.
For instance, SIGFPE (which now has an underground subcode which may mean
just about anything, depending on what system you are on..) could either have
an ARCHITECTED subcode, or be changed to a whole new array of codes, for
different things like Integer Overflow, Divide by zero, Floating-point
underflow and so on... 

After all, no matter how you bury your head in the sand, C is not the only
language out there. There's FORTRAN, Ada (soon coming to a computer near
YOU..), Pascal (that name again..), COBOL (no comments..) and so on. The
runtime semantics of such languages almost always force emission of UGLY
runtime code to do thins which can easily be caught by the hardware, but for
which U**X refuses to return a meaningful code.

Naturally, this will have to be defined to allow machines which do not have
a meaningful trap in a particular category to return a more generic code.

> Thus, the issue of the interface to the signal handler is not an issue raised
> by multiple versions of UNIX.  It *is* an issue if you have non-UNIX systems,
> but if you have to deal with non-UNIX systems, it's probably one of the least
> of the issues you will have to deal with.

This is not particularly a UNIX problem, it's an architecture problem.

Shankar.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/27/88)

In article <670016@hpclscu.HP.COM> shankar@hpclscu.HP.COM (Shankar Unni) writes:
>For instance, SIGFPE (which now has an underground subcode which may mean
>just about anything, depending on what system you are on..) could either have
>an ARCHITECTED subcode, or be changed to a whole new array of codes, for
>different things like Integer Overflow, Divide by zero, Floating-point
>underflow and so on... 

No matter how much work you put into an attempt to specify a fully
general (i.e. portable) floating-point exception status data structure,
I guarantee I can dream up a floating-point architecture that you
haven't accommodated.  There is nothing that forbids implementation-
dependent extensions for SIGFPE handlers, but you need to be aware
that they ARE implementation dependent.

Frankly, I think you should consider SIGFPE a fatal symptom that
indicates that you haven't designed a good enough algorithm; the
correct solution is to fix the algorithm, not interpret the state
of the floating-point processor once it's already too late.  The
simple use of SIGFPE is sufficient for this.

guy@gorodish.Sun.COM (Guy Harris) (04/27/88)

> I presume that by broken UNIX systems, you mean "most" UNIX system.

You presume incorrectly.  I know of no UNIX systems that *require* you to write
signal handlers as:

	handler(signo, code)
		int signo;
		int code;
	{
		...
	}

If you omit the "code" argument, they will still work.

> What am I going to do with that ubiquitous "SIGFPE"?

Either:

	1) do what 4BSD does, and rely on the fact that, in *most* current C
	   implementations, you can get away with the above;

	2) come up with a scheme where you can specify whether extra arguments
	   are to be delivered to a signal handler;

or

	3) use only the 4BSD signal mechanism, or the 4BSD-derived POSIX signal
	   mechanism, and in the "sigaction" structure declare the "sa_handler"
	   field as a pointer to a function with a variable-length argument
	   list:

		void	(*sa_handler)(int, ...)

1) will cause problems with ANSI C; "signal" takes an argument that is a
pointer to a function with one and only one argument, and the compiler will
give you a warning if you try to cast the address of a function with more
arguments to the type "pointer to a function with one argument".

3) is kind of rude.

2) is easy:

	struct sigaction {	/* speaking here in POSIX terms */
		union {
			void	(*sau_old_handler)(int signo);
			void	(*sau_new_handler)(int signo, int code);
		} sa_handler_union;
		sigset_t	sa_mask;
		int		sa_flags;
	};

	#define	SA_CLDSTOP	0xnnnn
	#define	SA_NEWHANDLER	0xmmmm
	...

	#define	sa_handler	sa_handler_union.sau_old_handler
	#define	sa_newhandler	sa_handler_union.sau_new_handler

If SA_NEWHANDLER is set, the "sau_new_handler" member is used; otherwise, the
"sau_old_handler" is used.  Non-stupid programs written to the POSIX interface
will set the flags field to a value that doesn't have the SA_NEWHANDLER bit
set, so they will work OK.  Programs that want to have handlers that receive
the signal code will have to set that bit, but that's life.

> > Thus, the issue of the interface to the signal handler is not an issue
> > raised by multiple versions of UNIX.  It *is* an issue if you have
> > non-UNIX systems, but if you have to deal with non-UNIX systems, it's
> > probably one of the least of the issues you will have to deal with.
> 
> This is not particularly a UNIX problem, it's an architecture problem.

Bullshit.  If you don't have the UNIX/POSIX signal mechanism, or the ANSI C
signal mechanism, you can easily define a signal mechanism that solves this
problem.  The *only* problem is that the ANSI C signal mechanism (which will
presumably, once ANSI C is adopted, spread its influence to the POSIX signal
mechanism) demands that signal handlers take only one argument.  Thus, this is
*at most* an ANSI C problem.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/29/88)

In article <51046@sun.uucp> guy@gorodish.Sun.COM (Guy Harris) writes:
>The *only* problem is that the ANSI C signal mechanism (which will
>presumably, once ANSI C is adopted, spread its influence to the POSIX signal
>mechanism) demands that signal handlers take only one argument.

There is no logical requirement that signal handlers registered via
sigaction() (new form of sigvec()) and those registered via signal()
must have the same interface, although it is easier to implement if
they do.  There are also other ways of obtaining extended information
than by passing it as arguments to the signal handler function.  I
can think of two obvious ones and there are probably others.

It is not ANSI C that introduced the single-argument signal handler;
that was existing practice everywhere until one day Berkeley decided
to change it on their systems.  Unfortunately Berkeley did not address
the portability issues when they made the change, thereby introducing
an unnecessary complication into what was to that point a simple
mechanism.  The whole signal approach is a botch anyhow; complicating
it without fixing it seems like a counterproductive direction.