calling non returning functions from java to JNI

391 views
Skip to first unread message

ymo

unread,
Jan 8, 2014, 5:27:22 PM1/8/14
to mechanica...@googlegroups.com
Hello All.

I have a need to transfer some objects between java and c/c++ functions. Here are my options.

producer:
JavaProducer ---> NativeSenderTightLoop

consumer:
NativeReceiverTightLoop ---> JavaConsumer

option a) make a blocking call to the native code via JNI. this would only come back after the end of the process meaning termination. The actual thread where this is running would be created from the java  code.

The benefit of this option is that i do not have to deal with creating threads on the native side. All i have to do is start the tight loop and only come back when the application is terminating.

option b) make a *non* blocking call to the native code via JNI. this would come back back right away to the calling function after initializing and creating the tight loop thread using native code.

The downside of this approach is that I have to create the actual thread where the tight loop will be running on the nativie side. Meaning i have to deal with cross platform issues like pthread_create or _beginthreadex in windows. All memory passing between the java and c++ is passed using off heap memory so referencing dangling pointers is not an issue. However ...

1) Which option would you recommend ?
2) Beside the porting issues what are the things that i should be careful about with making blocking/non blocking JNI calls like the above ? namely stuff like GC or safepoints or any other black art low level java regarding long running JNI calls.

 

Martin Thompson

unread,
Jan 8, 2014, 5:53:45 PM1/8/14
to mechanica...@googlegroups.com
As an alternative you could use a memory mapped file and exchange the objects in encoded format without needing JNI.

Peter Lawrey

unread,
Jan 8, 2014, 5:56:58 PM1/8/14
to mechanica...@googlegroups.com

If the C++ and Java is in the same process you don't even need a memory mapped file. Just use native memory.

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

ymo

unread,
Jan 8, 2014, 6:36:01 PM1/8/14
to mechanica...@googlegroups.com
Martin, i need a way to start and stop the threads/loops from a higher level api. The alternative is to resort to shell scripts which are not portable at least between (my target platforms) windows and linux.

I could use the memory mapped file as a control plane messaging. But i was hoping there is easier (read lazier) way by just going with jni for starting and stopping the threads. 

ymo

unread,
Jan 8, 2014, 6:38:53 PM1/8/14
to mechanica...@googlegroups.com
Peter, its a chicken and egg problem. I need a way to bootstrap the java and/or native threads. Ergo the option of starting the threads from either java or native side. I was not sure of what is implied by having a non returning JNI call. If it was going to mess up the gc in one way or another or create unkown issues.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-sympathy+unsub...@googlegroups.com.

Todd Lipcon

unread,
Jan 8, 2014, 6:46:18 PM1/8/14
to mechanica...@googlegroups.com
As far as I'm aware, it shouldn't be a problem to have a long-running call. JNI calls may safely block as long as you need without preventing GC. GC is only blocked if you use of the "critical section" methods which return direct views into heap objects (eg arrays).

If you look at various IO functions in the JDK, you'll see that normal blocking syscalls are made via JNI without any secret sauce.

-Todd


To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.

Martin Thompson

unread,
Jan 9, 2014, 3:23:18 AM1/9/14
to mechanica...@googlegroups.com
There is nothing wrong with a long running JNI call. The safepoint checks only occur when crossing the boundary. A memory mapped file, or allocated native memory, are the best way to then pass messages once your threads are started.


--

Gil Tene

unread,
Jan 9, 2014, 10:28:17 AM1/9/14
to mechanica...@googlegroups.com
I would certainly go for option A. Use Java to create the thread, and run in a long running pop JNI call. Share memory state with the native code via a direct buffer (mapped or not doesn't matter), and you can create the buffer either in Java (and pass it to the JNI method) or in JNI. Creating it in Java keeps it simple.

When you are in a JNI call (blocking or not doesn't matter) your thread is *at* a safepoint. The safepoint starts with the entry into JNI, and ends when it returns. If you make any JNI API calls to access Java state from within the native code, those individual calls each leave the safepoint, do their java state access, and then enter a safepoint again before returning.

The exception to this is what the JVM calls the JNI critical lock, which *may* be held between calls to GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical or between GetStringCritical and ReleaseStringCritical (the JVM actually has the option of making a copy and avoiding the lock, but in practice virtually all JVMs implement a GC blocking lock and grab the lock between these calls). Use of critical array and critical string access is HIGHLY discouraged, and is usually an indication of broken code (or code dating to before Java 1.4, when direct buffers were introduced in NIO), as the same logic can always be better achieved by using direct buffers.

ymo

unread,
Jan 9, 2014, 2:54:05 PM1/9/14
to mechanica...@googlegroups.com
Thank you all for your time and help. It is really appreciated.
Reply all
Reply to author
Forward
0 new messages