RFR: 8346388: Cannot use DllMain in libawt for static builds
Magnus Ihse Bursie
ihse at openjdk.org
Tue Dec 17 18:14:15 UTC 2024
To be able to properly support static builds on Windows in [JDK-8346377](https://bugs.openjdk.org/browse/JDK-8346377), we cannot use `DllMain`, for two reasons:
1) This is not called for statically linked libraries, and
2) There are multiple `DllMain` definitions throughout the JDK native libraries, causing name collisions.
While it could have been possible to keep the `DllMain` function for non-static builds and just use an alternative solution for static builds, I think it is preferable to have a single solution that works as well for both static and dynamic builds.
In this case, the `DllMain` function did two things:
1) At startup, it called SetModuleHandle. This has been moved to the `JNI_OnLoad` function, which is called by the JVM right after loading the DLL, or in the case of a static build, when the `awt` native library has been requested.
2) At DLL unload -- for debug builds only -- it "disabled" the mutexes for the DTrace and DMem debug systems. In this case, "disable" means writing NULL to the mutexes, causing any further calls to the continue without locking, since the enter/exit calls only do the locking if the mutex is not NULL. (This is pre-existing code so I am not discussing the soundness of this approach.)
But why did we need to do that? After the DLL unloading, which is done by Windows when the process is exiting, no code should be executing in AWT, right? No, wrong. There are three static objects, one instance of AwtDebugSupport and two instances of GDIHashtable, and the destructors of these objects are called by Windows at the time of process shutdown. I have not been able to confirm that the `DllMain` code is guaranteed to be called before the destructors are called, so I guess the fact that this ever worked has just been a lucky coincidence.
I have solved this by disabling the mutexes in the destructors themselves, thereby guaranteeing that they are disabled before the last few calls to the DTrace/DMem calls are made. There is no guarantee in which order these destructors are made, so I do the same on both locations. (There is no bad effect from calling these twice in a row, it's just setting a mutex to NULL).
Finally, I have wrapped the `DEF_JNI_OnLoad` function in `extern "C" { ... }`. This is needed since DEF_JNI_OnLoad is a macro that actually creates two functions, where one is a wrapper calling the other which has a generated name, and without this, the C++ name mangling messed things up. (To be clear: this means that the JNI_OnLoad function has never been called on Windows, but since it did not do anything of substance before, nobody noticed this.)
-------------
Commit messages:
- Merge branch 'master' into dll-main-in-libawt
- 8346388: Cannot use DllMain in libawt for static builds
Changes: https://git.openjdk.org/jdk/pull/22790/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=22790&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8346388
Stats: 61 lines in 3 files changed: 35 ins; 26 del; 0 mod
Patch: https://git.openjdk.org/jdk/pull/22790.diff
Fetch: git fetch https://git.openjdk.org/jdk.git pull/22790/head:pull/22790
PR: https://git.openjdk.org/jdk/pull/22790
More information about the client-libs-dev
mailing list