main() and exit() (was: Strange lint mumblings)

Chris Torek chris at mimsy.UUCP
Fri Dec 30 06:53:31 AEST 1988


In article <7082 at batcomputer.tn.cornell.edu> braner at batcomputer.tn.cornell.edu
(Moshe Braner) writes:
>On systems I have worked on, calling exit() links in most of the
>STDIO library modules, resulting in an executable program that is
>much bigger than it needs to be (in the case where you don't otherwise
>use STDIO).  Calling _exit() instead does not link in STDIO.

This is the wrong approach (which does not mean that no implementations
do it).  From a Unix slant, the difference is that exit() flushes
buffers iff using stdio, then calls _exit(); _exit() is the process-
termination system call.  From a dpANS slant, exit() calls the
registered atexit() [or is it onexit()?] functions, then causes the
program to terminate.

>Does YOUR system's startoff code (that calls main()) call exit() or _exit()?

Most call exit().  This does not have to suck in all of stdio.  Unix
systems have used various approaches to accomplish this.  With the
advent of the dpANS, the simplest approach is to have a single
reserved `atexit' slot for stdio, and have exit() provide a way
for stdio, if it is ever used, to register its own cleanup routine:

	/* exit.c */

	/*
	 * I have forgotten the details of atexit, so I am assuming
	 * that atexit() registers a (void (*)(void)), and returns
	 * success (0) / failure (nonzero).
	 */

	typedef void (*exitfn)(void);

	static exitfn exit_functions[32];
	static int next_exit_fn = 1;	/* slot 0 is for stdio */

	void __stdio_atexit(exitfn cleanup) {
		exit_functions[0] = cleanup;
	}

	int atexit(exitfn f) {
		if (next_exit_fn >= sizeof(exit_functions)/sizeof(exitfn))
			return (-1);	/* no room */
		exit_functions[next_exit_fn++] = f;
		return (0);
	}

	void exit(int code) {
		register int i;

		/*
		 * Call registered atexit functions, in reverse.
		 * If stdio has registered a cleanup function, it
		 * will be in slot 0 and therefore called last.
		 */
		for (i = next_exit_fn; --i >= 0;)
			if (exit_functions[i] != NULL)
				(*exit_functions[i])();
		/* now really exit */
		_exit(code);
	}

Then, in appropriate places within stdio, such as fopen and fdopen:

	extern void __stdio_cleanup(void);
	...
		__stdio_atexit(__stdio_cleanup);

>Do you like the way it is?

Yes.

>Other related observations/questions: exit() flushes stream I/O buffers.
>It also closes the files (releases the descriptors).  Who closes non-STDIO
>files (the ones you opened with open() rather than fopen())?  On my systems
>it seems that the OS closes the files . . . .

If your system has files, the OS should take care of closing them on
program termination.

>Finally, what percentage of YOUR programs do NOT use STDIO (buffered
>streams, fopen/fread/putc/puts/printf...)?

Certainly < 10%.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list