I just start learning JVM TI.
About the java command: java -agentpath:../tool.dll javaClass, I know that there is a Agent_OnLoad() method in dll and maybe it set some event callback method. And I know the jvm execute Agent_OnLoad() first and then execute javaClass.And the Agent_OnUnLoad() is also called by jvm.
Then the problem comes, how the jvm know when call Agent_OnUnLoad() method . At First, I think that after javaClass is executed jvm will calls Agent_OnUnload(), but then I discard this thought because at this time, maybe the dll is doing sth e.g. writing data to disk.
So how jvm know it is the right time to call Agent_OnUnLoad() method?
There is no standard mechanism defined to unload agent libraries. Agent_OnUnload will be called only before the VM termination, when all Shutdown hooks are completed.
Related
I'm making a little tool that handles a sort of exotic device, with lots of options to manage it etc. One of them would be to scan for tty ports, find the right one then throw the user to "minicom" with some parameters for example.
How can I make java completely exit while running a specific command, under certain condition, after such exit ?
Initial thoughts would be to use a bash script, scan the return value, communicate via files etc.A fully functional interactive serial console in Java would be the dream, but the ones I try right now can't seem to even find tty ports now.
Most processes on linux follow a call stack where process A calls process B which calls process C.
Wen process C terminates, the control goes back to process B, and so on.
It sounds like in this case you want java to call minimum, but when java is finished, return to the parent shell.
I am not aware of any way you can terminate a JVM upon a call to another process (returning to the JVM's parent when it terminates). Perhaps with some clever C calls using JNI, but that isn't really java anymore and could create new problems.
You could have the JVM wrap the target process and pass through the user inputs and outputs. Alternatively, use file communication, e.g. the java program writes the command-line to a file, that the parent bash script executes after the JVM terminates, but that is a bit of a kludge.
Hypothetical: Calling C++ code from Java is relatively straightforward. As I understand it, the C++ code is executed in the same thread as the Java code calling it (correct me if I'm wrong). If the C++ code then starts a new native thread with pthread_key_create(), can this thread call back into Java through JNI? If so, how is this possible, since the code would then be executing in a pthread instead of a Java thread on the JVM?
As I understand it, the C++ code is executed in the same thread as the Java code calling it (correct me if I'm wrong)
The JNIEnv is attached to a thread, you cannot share a JNIEnv between threads. Your native functions all receive a JNIEnv as the first argument so it corresponds to the current Thread's JNIEnv.
If the C++ code then starts a new native thread with pthread_key_create(), can this thread call back into Java through JNI?
All threads are Linux threads, scheduled by the kernel. They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then attached to the JavaVM. For example, a thread started with pthread_create can be attached with the JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv, and cannot make JNI calls.
If so, how is this possible, since the code would then be executing in a pthread instead of a Java thread on the JVM?
See previous response too ;) (the first two sentences)
More infos here and here.
In order to make upcalls to Java, a natively create thread should call first AttachCurrentThread or AttachCurrentThreadAsDaemon.
Take a look at this sample:
In this sample, you have a multi thread based code that calls Java code.
You can find full description here: http://jnicookbook.owsiak.org/recipe-no-027/
And source code is available here:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo027
I will not put all the codes here as it takes some space.
In fact, here: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo032,
you have more suitable sample for your. Where JVM calls C that calls JVM back invoking static method in Main class.
> java -Djava.library.path=${LD_LIBRARY_PATH}:./lib -cp target recipeNo032.Main
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
I will call JVM
From JVM
Have fun with JNI.
I'm loading a DLL and another program call a function I created. This function I made calls some java functions via JNI.
PS: I don't have the control of the DLL method call, it is called my another program.
When I create the JVM I do it with: JNI_CreateJavaVM.
After calling JNI methods I destroy the JVM with:
JNI_DestroyJVM().
The problem is that when the function in DLL is called, I create the JVM. But if the JVM is already loaded if fails becasuse of the following problem:
The problem:
Re-calling JNI_CreateJavaVM returns -1 after calling DestroyJavaVM
I know I can't call the JNI_CreateJavaVM twice because:
JNI_DestroyJVM(), it said "The JDK/JRE still does not support VM unloading, however." Just don't call it, and don't re-initialize it either.
1 - Why The JVM is still loaded in the memory after the DLL_PROCESS_DETACH?
2 - Is there a way to store a global variable in the DllMain?
Maybe I could store the (JavaVM *jvm); pointer, and not destroy the jvm after the dll call, so it would be destroyed when the process that call the dll is destroyed.
As I don't have the main program, I just have the DLL call, I can't store a global variable because the DLL_PROCESS_DETACH deletes every variable I created before.
Do not call JNI_DestroyJVM if you wish to run Java code more than once during the process lifecycle. Call DetachCurrentThread instead.
Before calling JNI_CreateJavaVM make sure JVM is not already created. Use JNI_GetCreatedJavaVMs to get an instance of the loaded JVM, then AttachCurrentThread to get JNIEnv* handle.
I have a Windows MFC application that:
(1) Loads the JVM (JNI_CreateJavaVM())
(2) Attaches the main thread to the JVM (AttachCurrentThread())
(3) Loads some Java classes and methods (FindClass() and GetMethodID() / GetStaticMethodID())
(4) Registers some native callbacks for use by Java code (RegisterNatives())
(5) Detaches the thread from JVM (DetachCurrentThread())
(6) Destroys the JVM (DestroyJavaVM())
All of the above functions succeed every other time I run the application. I know they succeed, because, additionally to the above, I interact with the application and successfully call Java static methods, and these Java methods successfully call my native callbacks. My application exits gracefully, and it is certain that the expected Java functions, and native callbacks, have been executed.
However, every other time that I run the application, the call to JNI_CreateJavaVM() fails (not populating the JavaVM *). Absolutely nothing changes between runs of the application. I simply run it once (successfully, even without doing anything except the above 6 steps), quit gracefully, run again, and it fails, back and forth. There are no exceptions to the back-and-forth success/failure - I can run it dozens of times, and it oscillates precisely every other time between success, and failing on the JNI_CreateJavaVM() line.
If necessary, I will paste more code. However, I hope somebody has an insight with what I've provided. (Note: this is a BCGSoft MFC property-sheet application, though I strongly doubt that matters.)
It looks like you are running into this bug (restated here) that is probably never going to be fixed.
Despite its name, DestroyJavaVM() does not actually destroy the JVM. What it does is signal the JVM that it should shut down, but the JVM actually waits until all the threads other than the Main thread have stopped before it actually shuts down. In fact, even then it does not fully clean up after itself, as the documentation states (quite cryptically): "The JDK/JRE still does not support VM unloading, however."
Also, I'm concerned about your step 2, "Attaches the main thread to the JVM". You do not need to attach the thread that created the JVM to the JVM and you may not detach that thread. If you really are doing that, then it's possible that is what is messing up your system. (The thread that creates the JVM is the JVM's "Main" thread. You only need to attach/detach other native threads to the JVM if they need access to it.)
By the way, JNI_CreateJavaVM() returns 0 on success, and you say it returns 0 the "failed" times, so in what sense is it failing? Which JVM (version, vendor) are you using?
I have a Java application that launches another java application. The launcher has a watchdog timer and receives periodic notifications from the second VM. However, if no notifications are received then the second virtual machine should be killed and the launcher will perform some additional clean-up activities.
The question is, is there any way to do this using only java? so far I have to use some native methods to perform this operation and it is somehow ugly.
Thanks!
I may be missing something but can't you call the destroy() method on the Process object returned by Runtime.exec()?
You can use java.lang.Process to do what you want. Once you have created the nested process and have a reference to the Process instance, you can get references to its standard out and err streams. You can periodically monitor those, and call .destroy() if you want to close the process. The whole thing might look something like this:
Process nestedProcess = new ProcessBuilder("java mysubprocess").start();
InputStream nestedStdOut = nestedProcess.getInputStream(); //kinda backwards, I know
InputStream nestedStdErr = nestedProcess.getErrorStream();
while (true) {
/*
TODO: read from the std out or std err (or get notifications some other way)
Then put the real "kill-me" logic here instead of if (false)
*/
if (false) {
nestedProcess.destroy();
//perform post-destruction cleanup here
return;
}
Thread.currentThread().sleep(1000L); //wait for a bit
}
Hope this helps,
Sean
You could also publish a service (via burlap, hessian, etc) on the second JVM that calls System.exit() and consume it from the watchdog JVM. If you only want to shut the second JVM down when it stops sending those periodic notifications, it might not be in a state to respond to the service call.
Calling shell commands with java.lang.Runtime.exec() is probably your best bet.
The usual way to do this is to call Process.destroy()... however it is an incomplete solution since when using the sun JVM on *nix destroy maps onto a SIGTERM which is not guaranteed to terminate the process (for that you need SIGKILL as well). The net result is that you can't do real process management using Java.
There are some open bugs about this issue see:
link text
OK the twist of the gist is as follows:
I was using the Process API to close the second virtual machine, but it wouldn't work.
The reason is that my second application is an Eclipse RCP Application, and I launched it using the eclipse.exe launcher included.
However, that means that the Process API destroy() method will target the eclipse.exe process. Killing this process leaves the Java Process unscathed. So, one of my colleagues here wrote a small application that will kill the right application.
So one of the solutions to use the Process API (and remove redundant middle steps) is to get away with the Eclipse launcher, having my first virtual machine duplicate all its functionality.
I guess I will have to get to work.
java.lang.Process has a waitFor() method to wait for a process to die, and a destroy() method to kill the subprocess.
You can have the java code detect the platform at runtime and fire off the platform's kill process command. This is really an refinement on your current solution.
There's also Process.destroy(), if you're using the ProcessBuilder API
Not exactly process management, but you could start an rmi server in the java virtual machine you are launching, and bind a remote instance with a method that does whatever cleanup required and calls System.exit(). The first vm could then call that remote method to shutdown the second vm.
You should be able to do that java.lang.Runtime.exec and shell commands.