In both C and C++, atexit
functions are called either inside exit
, or after main
returns (which notionally calls exit
: __libc_start_main(argc,argv) { __libc_constructors(); exit(main(argc,argv)); }
).
Is there a way to find out if we're inside the exit sequence? Destructors of C++ global and local statics are registered with atexit
, so your code can certainly be called into at this stage. (Interestingly, on some platforms if you try to create a C++ local-static object inside exit
, it deadlocks on the exit lock!)
My best attempt so far is as follows:
static bool mainExited = false;
static void watchMain() {
static struct MainWatcher {
~MainWatcher() { mainExited = true; }
} watcher;
}
When you want to watch for exit, you call watchMain()
, and mainExited
tells you at any time whether or not the exit sequence has begun -- except of course if a later-initialized local-static object is destructing!
Can the technique be improved to correct this, or is there another method that would work?
Aside - the use case!
While the problem is interesting from a language point-of-view (a bit like "can I tell if I'm inside a catch
block?"), it's also useful to outline a use-case. I came across the problem while writing some code which will be run with and without a JVM loaded (with either direct calls or calls via JNI). After the JVM exits, the C atexit
handlers are called, and JNI_OnUnload
is not called if the JNI shared library is not unloaded by the class loader.
Since the shared library's objects can be destructed both by explicit destruction (and should free their resources), and by cleanup at exit, I need to distinguish these two cases safely, since the JVM is gone by the time we reach the exit code! Basically without a bit of sniffing there's no way I can find in the JNI specs/docs for a shared library to know whether the JVM is still there or not, and if it's gone, then it's certainly wrong to try and free up references we have to Java objects.