Using direct ByteBuffers for native state

Prompted by Tom’s patch and comments about Classpath’s NIO, which, basically, is not very good, I started investigating writing a kqueue/kevent-based Selector implementation for OS X and BSDs that support it (FreeBSD, right?), and if that works out, maybe an epoll one for Linux.

One issue, of course, is how to keep track of native state for JNI methods. There are a bunch of solutions, like GCJ’s RawData thing (basically you declare a RawData field, and that magically gets treated just like any kind of pointer), or shoving a ponter into a long, but I don’t like any of these. I especially don’t like anything that requires using any significant number of JNI functions, because coding that way is just painful. And, once you’ve committed yourself to that, you have to manage your native allocations outside of the GC.

I had an idea for a different solution, which may be better: just allocate your native state as a direct ByteBuffer, and use GetDirectBufferAddress, casting the returned pointer as a pointer to your native structure type (in my case, for kevent, it would be just a pointer to one or two struct kevents). This is nice, because coding a JNI function that returns the sizeof (or offsetof, for a structure member) a data type is trivial. You even have the option of manipulating the structure in Java code, which is much easier than writing a JNI setter. The best part is that your native state is mostly managed by the GC — if you don’t need to allocate dynamic structures, you just allocate a single ByteBuffer, which will be deallocated by the GC. Once your wrapper Java object is collected, the native state is too, maybe with a simple finalize to clean up if you have to. You can even copy your native structures as easily as you copy between buffers — in the case of kevent, which takes a list of kevent structures, you can store the native state in each SelectionKey, then combine all the native states for all keys in a single ByteBuffer, and pass that single ByteBuffer to the JNI method! No translating of each Java SelectionKey to its native counterpart, and only one JNI call to get the direct buffer address!

We could, perhaps, go whole-hog here, and translate C structures into Java ones, so you can manipulate (or just plain read) those structs without diving into JNI. But even this may help — it’s already made my prototype kevent code really simple. I’ll let you know how it goes.