[comp.sources.misc] Keeping exit

gnu@hoptoad.UUCP (John Gilmore) (07/07/87)

[Cross posted to alt.sources because it is unmoderated; cross postings
to both mod and unmod groups, or to two mod groups, do not work
properly, so I couldn't send it to comp.sources.misc.  This article
contains an implementation of the draft C standard's atexit().]

zemon@felix.UUCP (Art Zemon) wrote:
> The original idea behind this was to keep the tools in
> /usr/bin and /bin small by not including the stdio library.
> Exit(), if it called _cleanup(), would bring in large chunks
> of otherwise unused code.
> 
> I think a better solution would be to rename the existing
> exit() to _exit() and create an exit() subroutine which
> calls _cleanup() and change the tools which don't use stdio
> to call _exit().  Whew!  I said all that in one breath. :-)

While Art's solution works, there is a cleaner solution than
requiring the programmer to call _exit if she doesn't use stdio.
Minix can remain small and still be fixed to work properly.

There is a library routine in SunOS called "on_exit()" which
registers a function so that it will be called when exit() is
called.  The Sun manual pages claim it is specific to SunOS.
However, an identical function called "atexit()" has appeared
in the draft C language standard, where it is claimed to be
descended from Whitesmiths C.  At any rate, it's an idea whose
time has come! 

This should be easy to implement; you make an array of 33 function
pointers (draft C std requires 32 and we need one for stdio) and an index,
say in <sys/atexit.h>:

#define MAXATEXIT	32
void (*__exits[MAXATEXIT+1])();
short __exit_i;

then rewrite exit.c:

#include <sys/atexit.h>

void
exit()
{
	while (__exit_i > 0)
		(*__exits[--__exit_i])();	/* Call them, LIFO */
	_exit();
}

In a separate file (atexit.c), so it doesn't get dragged in unless called,
you do:

#include <sys/atexit.h>

void
atexit(fun)
	void (*fun)();
{
	__exits[__exit_i++] = fun;
}

and then inside _flsbuf from stdio, do something like:

	...
	{
		static flaggola = 1;
		void cleanup();

		if (flaggola) {
			flaggola = 0;
			atexit(cleanup);
		}
	}
	...

(You have to make sure that _flsbuf will get called to output the first
character, rather than sticking it in the buffer, but that's easy.
Most stdio's do this anyway, so they can allocate the output buffer at
runtime.)

This ensures that if anything is in the stdio buffers, it will be
flushed upon exit, with only a minor space penalty on applications that don't
call stdio (33 function pointers, an int, and a few instructions in exit()).
It also adds a useful feature from the draft C standard.  Maybe for
Minix 1.3?
-- 
{dasys1,ncoast,well,sun,ihnp4}!hoptoad!gnu	       gnu@ingres.berkeley.edu
Alt.all: the alternative radio of the Usenet. Contributions welcome - post 'em