[net.bugs.4bsd] signal handling in 4.2

mark@cbosgd.UUCP (Mark Horton) (11/28/83)

In 4.2BSD, if a signal interrupts a system call, the system call
is resumed once the signal handler exits.  While it can be argued
that this behavior makes more sense, it breaks a lot of programs.
Some programs have code that looks like
	do {
		printf("prompt");
		caught = 0;
		osig = signal(SIGxxx, catch);
		read(0, buf, num);
		signal(SIGxxx, osig);
	} while (caught);

	catch(signum)
	{
		signal(SIGxxx, catch);
		caught = signum;
	}

In 4.1 and all other versions of UNIX, this arranges that when SIGxxx
(e.g. SIGINT or SIGCONT) comes in, the read terminates early and the
prompt is printed on the next trip through the loop.

in 4.2, the read resumes and only one prompt is printed, or in this
case you go into a loop.

I'm looking for a nice way to write clean portable code that will work with
this new system and still work with the old system.  ifdefs are acceptable
but it would be nice to keep the number down.

One way might be to use setjmp and have the signal routine longjmp to
the caller, replacing the loop.  Thus, you get
	#include <setjmp.h>
	jump_buf sigjmpbuf;

	setjmp(sigjmpbuf);
	caught = 0;
	printf("prompt");
	osig = signal(SIGxxx, catch);
	read(0, buf, num);
	signal(SIGxxx, osig);

	catch(signum)
	{
		signal(SIGxxx, catch);
		longjmp(sigjmpbuf);
		caught = signum;
	}

This strikes me as considerably less clear and more error-prone than
the old method.  Can anyone suggest a better way - perhaps a way to
make 4.2 go into "4.1 mode" without modifying the kernel or C library?

dmmartindale@watcgl.UUCP (Dave Martindale) (11/29/83)

A nice clean way to handle this would be to have the signal-handling
routine's return code indicate whether the system call which was
interrupted, if any, should be restarted.  This would still require
changes to old code which doesn't return anything meaningful from
the signal handler.  Maybe yet another flag, specified in the call to
signal that gives the handler's address?