Warning: ob_start(): non-static method wpGoogleAnalytics::get_links() should not be called statically in /home/w01fe/w01fe.com/wordpress/wp-content/plugins/wp-google-analytics/wp-google-analytics.php on line 259
A Blog. » Java

Archive for Java

C++ callbacks into Java via JNI made easy(ier)

I just finished writing a Java wrapper for a complex C++ library, and had a fair bit of trouble finding solutions to (or even basic documentation pertaining to) some of the problems that came up.

Things seem pretty easy if you just need to call some C++ functions from Java: you use JNI and do a little gruntwork to translate data to and from Java objects, or let SWIG do the heavy lifting for you. However, in my case things were harder, because the library is multithreaded (using boost threads) and makes heavy use of callbacks into the client (i.e., Java).

The main complication is that each native thread that calls a Java method must do so through its own JNIEnv pointer, obtained by calling AttachCurrentThread on a JavaVM instance. Each such native thread (which may be created and managed by code you can’t change) must eventually be detached from the JVM by calling DetachCurrentThread within it, or it seems memory leaks and JVM shutdown issues can result. There is no obvious way to detach the thread from the outside, so if you let the thread die or get away before it calls DetachCurrentThread you’re stuck.

Since a C++ wrapper for the Java callbacks is needed anyway, one easy solution is to attach before each callback and detach afterwards. However, this may be very expensive; I haven’t measured the cost, but one post I found quoted a factor of 6 slowdown. My alternative solution uses boost::thread_specific_ptr to detach each native thread just before it dies:

#include <boost/thread/tss.hpp>
 
static JavaVM *vm = NULL;
 
class ThreadJNIEnv {
public:
    bool _detach;
    JNIEnv *env;
    ThreadJNIEnv() {
        cout << "Attaching " << boost::this_thread::get_id() << endl;
        vm->AttachCurrentThread((void **) &env, NULL);
        ASSERT(env != NULL);
        _detach = true;
    }
 
    ThreadJNIEnv(JNIEnv *e) {
        env = e;
        _detach = false;
    }
 
    ~ThreadJNIEnv() {
        if (_detach) {
            cout << "Detaching " << boost::this_thread::get_id() << endl;
            vm->DetachCurrentThread();
        }
    }
};
 
static boost::thread_specific_ptr<ThreadJNIEnv> envs;
 
JNIEnv *getJNIEnv(){
    ThreadJNIEnv *tenv = envs.get();
    if (tenv == NULL) {
        tenv = new ThreadJNIEnv();
        envs.reset(tenv);
    }
    return tenv->env;
}
 
bool init(JNIEnv *env) {
   if (!env->GetJavaVM(&vm) < 0) return false;
   envs.reset(new ThreadJNIEnv(env));
   return true;
}

If your main function is in Java, you initialize the library by calling init(env) with the current thread’s JNIEnv (with multiple Java threads, you may have to take care). If it’s C++, you just set “vm” directly when you create the JVM instance.

Then, any function not in a direct JNI call just uses getJNIEnv() to get a JNIEnv pointer that’s valid for the current thread. This will work correctly both for indirect calls from Java, and from native threads, which will be automatically attached on the first call to getJNIEnv and automatically detached before death.

Seemed to work for me on Ubuntu; YMMV.

Comments (5)

Computing java.util.List hashCode()s back-to-front

For some applications, it could be desirable to compute java.util.List hashCode()s backwards, recursively from back to front, rather than front-to-back as defined in the API [1]. For instance, in Clojure this would enable computing the hash values for all of the rests of a seq for free while computing its hash value. This requires just a tiny bit of math and understanding of modular arithmetic. Clojure code showing how this can be done follows.

[1] http://java.sun.com/j2se/1.4.2/docs/api/java/util/List.html#hashCode()

(defn forward-hash "How hashCode() is defined in java.util.List"  [s]
  (loop [s (seq s) h (int 1)]
    (if s 
        (recur (rest s) (int (unchecked-add (unchecked-multiply h 31) (hash (first s)))))
      h)))
 
 
(def int-pow 
     (memoize 
      (fn [x n]
	(let [x (int x) n (int n)]
	  (cond (zero? n) 1
		(even? n) (let [h (int-pow x (/ n 2))] (unchecked-multiply h h))
		:else     (unchecked-multiply x (int-pow x (dec n))))))))
 
(defn backward-hash "Compute the same value as forward-hash, but back-to-front."  [s]
  (let [s (seq s) p (int-pow 31 (count (rest s)))]
    (if s 
        (unchecked-add (unchecked-multiply 30 p)
		       (unchecked-add (int (backward-hash (rest s)))
				      (unchecked-multiply (int (hash (first s))) p)))
	1)))
 
 
user> (map #(% (vec (range 1000))) [forward-hash backward-hash #(.hashCode %)])
(133786869 133786869 133786869)

Update: I posted this on the Clojure issue page here. Note a small caveat there: it is not allowed by Java that (.equals [] (seq [])), so Clojure collections and seqs cannot be comparable in general. However, everything carries through for non-empty seqs and collections.

Comments