signal() help needed

Chris Torek chris at umcp-cs.UUCP
Mon Sep 15 00:31:36 AEST 1986


In article <11997 at watnot.UUCP> cagordon at watnot.UUCP (Chris Gordon) writes:
>If I have a function [func() of] (no args) ... And I wish to catch
>SIGINT and SIGQUIT to execute this function just before an exit(0),
>what would be the EXACT signal() statement (and do I need any others)?

This is a Unix question, not a C question, so I have directed followups
to net.unix.

SIGINT and SIGQUIT are, as are all signals, set with the `signal'
system call:

	int (*old_disposition)();
	int new_catcher();

	old_disposition = signal(SIGINT, new_catcher);

Writing

	int userquit();

	signal(SIGINT, userquit);
	signal(SIGQUIT, userquit);

is a common mistake that shows no problems under `modern' systems
using `modern' shells and job control.  However, on any 4BSD or V7
system using `sh', this has the wrong effect on background jobs.
The Bourne shell starts background jobs with keyboard signals
ignored, so that the interruption of a foreground job will not also
interrupt those same background jobs.  It is therefore necessary
to first determine that signals are not being ignored:

	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		(void) signal(SIGINT, userquit);

This, however, opens a window during which interrupts are ignored
---lost forever.  An equally unsatisfactory alternative is

	if (signal(SIGINT, userquit) == SIG_IGN)
		(void) signal(SIGINT, SIG_IGN);

Prior to the job control mechanism in 4.1BSD, there was no way to
atomically test the state of a signal.  In 4.1, one could write

	sigblock(SIGINT);
	if (signal(SIGINT, userquit) == SIG_IGN)
		(void) signal(SIGINT, SIG_IGN);
	sigrelse(SIGINT);

(requring compilation with `-ljobs').  This holds off any keyboard
interrupts until after the signal disposition has been properly set.
In 4.2 and 4.3BSD, the code becomes

	int omask = sigblock(sigmask(SIGINT));

	if (signal(SIGINT, userquit) == SIG_IGN)
		(void) signal(SIGINT, SIG_IGN);
	(void) sigsetmask(omask);

In 4.2BSD it is necessary to first define sigmask:

	#define sigmask(s) (1 << ((s) - 1))

In 4.3BSD the sigmask macro is defined in <signal.h>.

To return to the original problem, assuming that func() does not
itself exit, you must first write a version that does:

	quitfunc()
	{

		func();
		exit(0);	/* exit(0) implies success, which
				   seems rather odd in a quitting
				   routine.  But on with the code.... */
	}

	set(sig, act)
		int sig, (*act)();
	{
		int omask = sigblock(sigmask(sig));

		if (signal(sig, act) == SIG_IGN)
			(void) signal(sig, SIG_IGN);
		(void) sigsetmask(omask);
	}

	...
		set(SIGINT, quitfunc);
		set(SIGQUIT, quitfunc);

This is still not entirely reliable, as exit() flushes stdio buffers,
but signals may occur when stdio's internals are not in a flushable
state.  In practice, this is often not a problem.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris at umcp-cs		ARPA:	chris at mimsy.umd.edu



More information about the Comp.lang.c mailing list