[comp.lang.c] Any way to catch exit

bpendlet@esunix.UUCP (Bob Pendleton) (08/18/88)

I'd have thought this was trivial, except that I've spent 2 days
RTFMing and can't find the answer.

I'm writing a library that needs to do some clean up when the program
that is using it is done. Just because I'm such a nice guy I'd like to
let the user program just terminate, any old way, a signal or by
exit() and just automagically do the clean up. Well I can catch a
signal, but I haven't found a portable way to "catch" exit(). I found
the SunOS on_exit() routine, nice. But ULTRIX doesn't seem to have
one, and I've been told that this is going to have to port to System
V.

So, is there a portable way for a routine to dectect when the program
it is part of is trying to exit()?


			Bob P.
-- 
Bob Pendleton @ Evans & Sutherland
UUCP Address:  {decvax,ucbvax,allegra}!decwrl!esunix!bpendlet
Alternate:     utah-cs!esunix!bpendlet
        I am solely responsible for what I say.

U23405@UICVM (Michael J. Steiner) (08/25/88)

The easiest way to do some cleaning up when exiting your program would
probably be to call a special function that would do the cleaning up, with
the last statement of that function being exit(), like this:

          void my_exit()
          {
               /* Clean up */
               ...
               exit();
          }

If this isn't what you're talking about, please tell me.

                                                 Michael Steiner
                                                 Email: U23405@UICVM.BITNET

lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (08/27/88)

One solution that I have employed is to define my own exit routine.
When the program terminates my exit routine is called, and does what
I want.

	void exit(e)
		int e;
	{
		...whatever...
		_exit(e);	/* still need this sucker */
	}

This probably is non-portable but should solve your problem (if I
understood it correctly).

If you have the source code to popen(3) look at it for another example.

-- 
Larry Cipriani, AT&T Network Systems, Columbus OH, cbnews!lvc lvc@cbnews.ATT.COM

leo@philmds.UUCP (Leo de Wit) (08/28/88)

In article <967@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes:
>One solution that I have employed is to define my own exit routine.
>When the program terminates my exit routine is called, and does what
>I want.
>
>	void exit(e)
>		int e;
>	{
>		...whatever...
>		_exit(e);	/* still need this sucker */
>	}
>
>This probably is non-portable but should solve your problem (if I
>understood it correctly).

One of the problems looming up is that exit() should flush stdio buffers.
(this should be part of ...whatever...). I don't know how that can be
done in a portable manner. Ultrix seems to use _cleanup() at this point.
There is a funny thing about _cleanup():
It is called without parameters. If I run the following program through adb:

main()
{
    exit(0);
}

then _cleanup() does just: ret.

If I run the following however:

main()
{
    printf("12345");
    exit(0);
}

then _cleanup() does a lot of stuff. It seems that if stdio is not used
a simple version of _cleanup is used; if it IS used, a complicated one
is used that does a _filewalk() or something. Probably has something to
do with keeping binary sizes small, but I can't figure out how you can
have several _cleanup() 's in one library. Anyone knows?

                               Leo.

bill@proxftl.UUCP (T. William Wells) (08/29/88)

In article <771@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes:
:                                               Probably has something to
: do with keeping binary sizes small,

Yes.  Loading the stdio _cleanup means loading a substantial part
of stdio as well.

:                                     but I can't figure out how you can
: have several _cleanup() 's in one library. Anyone knows?
:
:                                Leo.

This is easy on a UNIX system.  You define __iob or whatever the
FILE pointers point to in the file where you want the fancy
_cleanup routine to go.  You then place the exit and then the
dummy _cleanup right after it.  You have to give the two object
files different names, but that is easy.  The names I have seen
are cleanup.o and fakcu.o.  So, if the program references stdio
anywhere, it will reference __iob.  When the linker finds the
first _cleanup, it will load it because of the __iob.  Then exit
comes along and uses the already loaded _cleanup so the second
one is ignored.  On the other hand, if stdio is not referenced,
the first _cleanup is ignored because there is no reference to
it; the exit is loaded because every program references exit, and
that forces the loading of the second _cleanup.

There are several variations on this theme, but as far as I know
they all depend on library ordering tricks.

---
Bill
novavax!proxftl!bill

henry@utzoo.uucp (Henry Spencer) (08/29/88)

In article <771@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes:
>... It seems that if stdio is not used
>a simple version of _cleanup is used; if it IS used, a complicated one
>is used that does a _filewalk() or something. Probably has something to
>do with keeping binary sizes small, but I can't figure out how you can
>have several _cleanup() 's in one library. Anyone knows?

I don't know how Ultrix is doing it, but the way V7 did it was to use a
non-ranlibbed libc and have two versions of _cleanup, one preceding
exit and the other following it.  The first one was tied to stdio by
some carefully-crafted external references, so it would be picked up if
stdio was in use, while the second one would be picked up if the first
wasn't.  You can't do this with a single ranlibbed library, at least not
that I know of, but you can pull the same trick by using more than one
library and getting the search order right.

It is in any case somewhat academic, since stdio is practically universal
these days.
-- 
Intel CPUs are not defective,  |     Henry Spencer at U of Toronto Zoology
they just act that way.        | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

greggy@infmx.UUCP (greg yachuk) (08/30/88)

Microsoft C defines a function `onexit()' which takes the address of a
function that is to be executed when the program terminates normally.
Up to 32 functions may be specified, which are executed in a LIFO manner.
The functions may not take any parameters.

The MSC 5.0 manual also states that there is a similar ANSI-standard
functions named `atexit()'.  I don't know anything about it.

Greg Yachuk		Informix Software Inc., Menlo Park, CA	(415) 322-4100
{uunet,pyramid}!infmx!greggy		why yes, I DID choose that login myself

gwyn@smoke.ARPA (Doug Gwyn ) (08/31/88)

In article <388@infmx.UUCP> greggy@infmx.UUCP (greg yachuk) writes:
>Microsoft C defines a function `onexit()' ...
>The MSC 5.0 manual also states that there is a similar ANSI-standard
>functions named `atexit()'.  I don't know anything about it.

onexit() originated with Whitesmiths, Ltd.  Somewhere in the course
of developing the proposed ANSI C standard, a similar but incompatible
function of the same name was present for several drafts.  However,
it was possible to take the revised onexit() and substantially simplify
the interface, and so we did.  I suggested calling the result atexit()
so that Whitesmiths customers would not find their use of onexit()
broken.  Unfortunately, IBM and Microsoft jumped the gun and added the
interim version of onexit() to their C implementations.  Not only is it
incompatible with the original Whitesmiths version, it isn't the
function finally adopted by X3J11 for this purpose.  (At least it is
possible to implement both simultaneously!)

Incidentally, there are still some unintended ambiguities in the
specification of atexit(), but (as I recall; my notes are not at hand)
the Committee was unwilling to tighten up the spec at this point.  The
main ambiguity is that an exit handler SHOULD be unregistered before
it is invoked, so that a reentry to exit() from an exit handler will
not cause an infinite recursion, but we hadn't thought of that until
a member of the public pointed it out.  I hope that implementors will
be careful to do this.  Perhaps I should update my public-domain
implementation and repost it.