[net.lang.c] ANSI X3J11 onexit

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/17/86)

/*
	onexit, exit -- register function to be invoked at program termination

	last exit:	17-Jun-1986	D A Gwyn

	Portable version that invokes the previous implementation of exit(),
	now renamed __exit(), just to show how onexit() can be implemented.
*/

#if __STDC__

#include	<stdlib.h>		/* defines onexit_t */

#define	VOID	void			/* empty argument list in prototype */
#define	INT	int			/* int argument in prototype */

#else	/* pre-X3J11 C */

#define	VOID	/* nothing -- prototypes not supported */
#define	INT	/* nothing -- prototypes not supported */

typedef	void	(*onexit_t)(VOID);	/* should be general enough */
/* The above line really needs to be put into a <stdlib.h> header! */

#define	NULL	0

#endif	/* __STDC__ */

extern void	__exit(INT);		/* pre-onexit version of exit();
					   typically _cleanup() then _exit() */

/* functions are registered in a linear list with explicit count: */

#ifndef	MAX_CALLS			/* # functions that can be registered */
#define	MAX_CALLS	32		/* minimum required by X3J11 */
#endif

static onexit_t	(*list[MAX_CALLS])(VOID);	/* function registration list */
static int	n_calls = 0;		/* # functions registered so far */


onexit_t
onexit( func )
	onexit_t	(*func)(VOID);	/* -> function to be registered */
	{
	if ( func == NULL		/* safety net for incorrect usage */
	  || n_calls == MAX_CALLS
	   )
		return (onexit_t) NULL;	/* registration failure */
	else	{
		list[n_calls++] = func;	/* register the function */

		return (onexit_t) func;	/* non-NULL => success */
		}
	}


void
exit( status )
	int	status;			/* termination status code */
	{
	/* execute functions in reverse order of registration */

	while ( n_calls != 0 )
		(void) (*list[--n_calls])();

	__exit( status );		/* former version of exit() */

	/*NOTREACHED*/
	}

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/18/86)

I have just posted a public-domain implementation of the ANSI X3J11
(draft C language standard) "onexit" function to net.lang.c (INFO-C),
as I promised during the last couple of weeks.  The main purpose is
to help implementors who thought that this would be too much trouble
and were therefore objecting to onexit().

As a result of actually implementing this function, I am now in a
position to criticize the interface.  In the May 1, 1986 Draft
standard (X3J11/86-074), the new defined type "onexit_t" is used in
two different contexts: as the return value type of the user's
pre-termination function and as the value returned by onexit() to
indicate success or failure of function registration.  The former
usage should certainly be (void), since there is no way to make use
of any value that a pre-termination function might return.  The
latter usage need only be a simple (int), but the current Draft
states that it must be comparable to a NULL pointer constant, which
unfortunately the Draft has strongly indicated should be (void *)0
instead of the traditional 0.  A much cleaner interface would be:

	int onexit(void (*func)(void));

which would return zero or not depending on whether the function
was successfully registered.  I think the current awkward design is
an artifact of the original Whitesmiths, Ltd. implementation which
required each pre-termination function to return a pointer to the
next most recently registered function, so that exit() could
traverse the list of function pointers without having to maintain
private storage for them.  However, that's not necessary under the
current design, so I would like to see the interface cleaned up.

ado@elsie.UUCP (Arthur David Olson) (06/21/86)

In article <1438@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn) writes:
> I have just posted a public-domain implementation of the ANSI X3J11
> (draft C language standard) "onexit" function. . .I am now in a position to
> criticize the interface. . .A much cleaner interface would be:
> 
> 	int onexit(void (*func)(void));
> 
> which would return zero or not depending on whether the function
> was successfully registered.  I think the current awkward design is
> an artifact of the original Whitesmiths, Ltd. implementation. . .

Having suggested the same myself (see mod.std.c archives), I'll second the
motion. . .with a qualification.  Since there are existing (Whitesmiths)
implementations with an interface different from that described above, it's
almost surely best to use a different name for the above interface--for
example,

 	int atexit(void (*func)(void));

This avoids surprises when moving existing source code to an ANSI standard
system.
--
	UUCP: ..decvax!seismo!elsie!ado		ARPA: elsie!ado@seismo.ARPA
	DEC, VAX, Elsie & Ado are Digital, Borden & Shakespeare trademarks.