Open hongxuchen opened 6 years ago
My impression is that one can only have exactly one JVM in one process in total, and not sequentially: https://docs.rs/rucaja/0.4.2/rucaja/struct.Jvm.html#method.new
If i understand correctly, sharing the same JVM from different Rust threads should be safe, since we attach/detach using JvmAttachment (AttachCurrentThread()
+ DetachCurrentThread()
). There still could be bugs, since i haven't tried what you are doing.
An alternative could be to use different Rust processes.
And thanks by the way for using Rucaja. I am interested in making it more usable, so your feedback is very appreciated.
I have no deep JNI knowledge myself. @fpoli, @Treyzania, @tupshin, @Dushistov do you have any experience regarding multithreading and JNI? Is the above approach sufficient?
I'm also not an expert, but I just found that "according to docs, only one thread can use use JVM at a time". So, it should be possible by using a Mutex<Jvm>
(or some other technique).
@kud1ing and @fpoli Thanks so much for your help! I think I've to choose another approach.
@kud1ing I'm a bit late to this party, but I would assume that we could restructure the APIs a bit so that we always return a Mutex<Jvm>
or some preferably opaque type that makes sure that only one thread is actually interacting with the JVM at a time. This would allow us to automagically issue the call to DetachCurrentThread
in the Drop
implementation for whatever this type returns when we try to "attach" to the JVM, which would be super awesome!
Unless we want to make Jvm
be !Send
, which would fix the problem, but in a very shitty way. As I side note, I can't figure out why anybody would need !Send
outside of wrapping code written in other languages (OpenGL contexts are per-thread, etc.) or maybe in a kernel.
EDIT: I'm now realizing that Jvm
is naturally !Send
because of how Rust auto-derives things. I'd need to think on it a bit as I am far from a JNI expert. Worst-case scenario if we can't find a reliable way to pass it between threads somehow would be to have a "JNI thread" that actually owns the JVM, that we can pass a closure to be queued to be executed (with std::sync::mspc
or something like it), and then layer some abstractions on top of that to make it easy to simple things with. This is so suboptimal, but it's a worse-case scenario, honestly. The fact that the JVM can spawn its own threads that can potentially have references to things that we allocated makes things all kinds of complicated. So those are more concerns (perhaps translating using Box::into_raw
and Box::from_raw
?) for dealing with passing things into the JVM.
My code is in a multi-thread setting, inside each thread, there is a need to call jvm functions.
I find that the "jvm" instance itself cannot be constructed separately inside each thread, by loading the classpath with proper options. In this case, it will panic with a message:
This alternative seems to be putting JVM construction code before spawning threads and then passing as parameters.
The problem is that I'm not quite sure whether this will cause data race internally at the JVM side.
Since I know little about JNI and would like to be merely a "user" of rucaja, Could you please advise?