|
|
Java Native Interface Programming |
In JDK1.1, the Java Virtual Machine is shipped as a shared library (or dynamic link library on Win32). You can embed the Java VM into your native application by linking the native application with the shared library. The JNI supports an Invocation API that allows you to load, initialize, and invoke the Java Virtual Machine. Indeed, the normal way of starting the Java interpreter,java, is no more than a simple C program that parses the command line arguments and invoke the Java Virtual Machine through the Invocation API.Invoking the Java Virtual Machine
As an example, we will write a C program to invoke the Java Virtual machine and call the
Prog.mainmethod defined inProg.java:public class Prog { public static void main(String[] args) { System.out.println("Hello World" + args[0]); } }The C code ininvoke.cbegins with a call toJNI_GetDefaultJavaVMInitArgsto obtain the default initialization settings (heap size, stack size, and so on). It then callsJNI_CreateJavaVMto load and initialize the Virtual Machine.JNI_CreateJavaVMfills in two return values:Note that after
jvmrefers to the created Java Virtual Machine. It can be later used to, for example, destroy the Virtual Machine.envis a JNI interface pointer that the current thread can use to access Java features, such as calling a Java method.JNI_CreateJavaVMsuccessfully returns, the current native thread has bootstrapped itself into the Java Virtual Machine, and is therefore running just like a native method. The only difference is that there is no concept of returning to the Java Virtual Machine. Therefore, the local references created subsequently will not be freed until you callDestroyJavaVM.Once you have created the Java Virtual Machine, you can issue regular JNI calls to invoke, for example,
Prog.main.DestroyJavaVMattempts to unload the Java Virtual Machine. (The JDK 1.1 Java Virtual Machine cannot be unloaded, therefore DestroyJavaVM always returns an error code.)You need to compile and link
invoke.cwith Java libraries shipped with JDK1.1. On Solaris, you can use the following command to compile and linkinvoke.c:cc -I<where jni.h is> -L<where libjava.so is> -ljava invoke.cOn Win32 with Microsoft Visual C++ 4.0, the command line is:cl -I<where jni.h is> -MT invoke.c -link <where javai.lib is>\javai.libRun the resulting executable from the command line. If you get the following error message:
Unable to initialize threads: cannot find class java/lang/Thread Can't create Java VMThis means that yourCLASSPATHenvironment variable is not set up properly to include Java system classes. On the other hand, if the system complains that it cannot find eitherlibjava.so(on Solaris) orjavai.dll(on Win32), addlibjava.sointo yourLD_LIBRARY_PATHon Solaris, or addjavai.dllinto your executable path on Win32. If the program complains that it can not find the classProg, make sure the directory containingProg.classis in theCLASSPATHas well.If you are building a window (as opposed to a console) application on Win32, you must explicitly set the
CLASSPATHslot in the Virtual Machine initialization structure. Window applications do not read the environment strings like console applications do. In general, it always a good idea to specify theCLASSPATHbefore you callJNI_CreateJavaVM, rather than relying on the environment variable settings when the program is run.Attaching Native Threads
The Invocation API also allows you to attach native threads to a running Java VM, and bootstrap themselves into Java threads. This requires that the Java Virtual Machine internally uses native threads. In JDK 1.1, this feature only works on Win32. The Solaris version of Java Virtual Machine uses user-level thread support and is therefore incapable of attaching native threads. A future version of JDK on Solaris will support native threads.Our example program,
attach.c, therefore, will only work on Win32. It is a variation ofinvoke.c. Instead of callingProg.mainin the main thread, the native code spawns five threads, and then just waits for them to finish before it destroys the Java Virtual Machine. Each thread attaches itself to the Java Virtual Machine, invokes theProg.mainmethod, and finally detaches itself from the Virtual Machine before it terminates.All local references belonging to the current thread will be freed when
DetachCurrentThreadis called.Limitations of the Invocation API in JDK1.1
As mentioned above, there are a number of limitations of the Invocation API implementation in JDK1.1.These problems will be fixed in future releases of the JDK.
- The user-level Java thread implementation on Solaris requires the Java VM to redirect certain Solaris system calls. The set of redirected system calls currently includes
read,readv,write,writev,getmsg,putmsg,poll,open,close,pipe,fcntl,dup,create,accept,recv,send, and so on. This may cause undesirable effects on a hosting native application that also depends on these system calls.- You cannot attach a native thread to the user-thread based Java Virtual Machine on Solaris.
AttachCurrentThreadsimply fails on Solaris (unless it is called from the main thread that created the Virtual Machine).- You cannot unload the Java Virtual Machine without terminating the process. The
DestroyJavaVMcall simply returns an error code.
|
|
Java Native Interface Programming |