RFR: 8349178: runtime/jni/atExit/TestAtExit.java should be supported on static JDK

Jiangli Zhou jiangli at openjdk.org
Wed Feb 5 03:07:14 UTC 2025


On Tue, 4 Feb 2025 01:10:34 GMT, Jiangli Zhou <jiangli at openjdk.org> wrote:

> Please review runtime/jni/atExit/TestAtExit.java test change:
> 
> - Remove `BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libatExit := java.base:libjvm`. Don't explicitly link with libjvm, because it adds libjvm.so as a recorded dependency to libatExit.so (on Linux for example). That requires libjvm.so must be resolved and loaded successfully when libatExit.so is loaded. The static JDK (e.g. static-jdk image) does not provide a libjvm.so for runtime usage.
> - Instead of calling the following functions directly in libatExit.c, change to look up the functions and calls them using the retrieved function addresses:
>   - JNI_GetDefaultJavaVMInitArgs
>   - JNI_GetCreatedJavaVMs
>   - JNI_CreateJavaVM
> 
> On Linux (and similar) platform, there is no need to call `dlopen` for libjvm in libatExit.c explicitly, because the VM must already be loaded by the time when the libatExit native code is executed. Using `RTLD_DEFAULT` can "find symbols in the executable and its dependencies, as well as symbols in shared objects that were dynamically loaded with the RTLD_GLOBAL flag" (see https://man7.org/linux/man-pages/man3/dlsym.3.html).  https://github.com/openjdk/jdk/blob/9b49597244f898400222cfc252f50a2401ca3e2f/src/java.base/unix/native/libjli/java_md.c#L533 is where we `dlopen` libjvm with `RTLD_GLOBAL` for unix platform.
> 
> For Windows platform, I added Windows specific code to get the loaded `jvm.dll` first. If it can't find loaded `jvm.dll`, it then get the handle of the executable running the current process. The returned handle is used for finding the function addresses. 
> 
> TestAtExit passes with https://github.com/jianglizhou/jdk/actions/runs/13124407248/job/36619759000. TestAtExit also pass on static-jdk with my local jtreg run.

I want to answer the question carefully to avoid possible confusions, so the comment below may provide extra information (also verbose) than just addressing the question. Please let me know if anything is unclear.

>   and as noted launchers have the choice of either linking with libjvm.so or else using dynamic lookup. The former doesn't work with a static JDK (can we link with libjvm.a?). 

Yes. A launcher executable can explicitly link with a native library, either using .so (shared library)  or .a (static library) if the launcher code has any direct references to symbols defined in the native library. The launcher can also choose to do dynamic symbol lookup and avoids the need for explicitly linking with the native library. 

If a launcher executable is linked with libjvm.so at build time, it requires libjvm.so to be resolved (normally from the RPATH) and loaded successfully when the launcher executable is loaded. Otherwise the executable fails to load and start due to the missing libjvm.so dependency. If a launcher executable is statically linked with libjvm.a, runtime does not try to find the libjvm.a since that is already built into the executable.

Same for a shared library (e.g. the libatExit.so used by the test) linked with libjvm.so, the shared library fails to be loaded if libjvm.so do not present at runtime.  

If launcher code choose to use dynamic symbol lookup and avoids linking with libjvm.so, the launcher code can support both dynamic case and static case. The `java` launcher does that.

> So in the context of fixing a couple of tests this is okay.

Yeah, since there are just few cases in the tests, I feel fixing these tests seem to be a good choice.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/23431#issuecomment-2635599602


More information about the build-dev mailing list