A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/bytedeco/javacpp/issues/486 below:

Callback thread safety issue · Issue #486 · bytedeco/javacpp · GitHub

In our project, Java implemented callback is passed to native code. The function signature looks like std::function<bool(uint64_t)>.

        infoMap.put(new Info("std::function<bool(uint64_t)>").pointerTypes("FilterFunction"));

    public static class FilterFunction extends FunctionPointer {
        static { Loader.load(); }
        /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
        public    FilterFunction(Pointer p) { super(p); }
        protected FilterFunction() { allocate(); }
        private native void allocate();
        public native boolean call(@Cast("uint64_t") long key);
    }

In our testing program, a ThreadPool is created. Each thread runs the same logic, creating one callback and passing the callback to native code. Pseudo code looks like this

        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount);
        List<Future> futures = new ArrayList<>();
        NativeClass2 processor = new ...;
        for (int i = 0; i < threadCount; i++) {
            futures.add(executor.submit(()->{
                    NativeClass1 ctx = new ...;
                    ctx.set_filter(new FilterFunction() {
                        @Override
                        public boolean call(@Cast("uint64_t") long key) {
                            return false;
                        }
                    });
                   for (Query q : queries) {
                        processor.process(ctx, q);
                   }
           });
        }

When there are 29 or less threads created, the testing program runs fine. However creating 30 or more threads will lead to crashing(core dump).

#0  0x00007efef0bb88af in raise () from /lib64/libc.so.6
#1  0x00007efef0bba4aa in abort () from /lib64/libc.so.6
#2  0x00007efef0417ee9 in os::abort(bool) () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#3  0x00007efef063f03a in VMError::report_and_die() () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#4  0x00007efef0422095 in JVM_handle_linux_signal () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#5  0x00007efef04150a8 in signalHandler(int, siginfo_t*, void*) () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#6  <signal handler called>
#7  0x00007efef01dc4bf in jni_invoke_nonstatic(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*) [clone .constprop.235] ()
   from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#8  0x00007efef01e66aa in jni_CallBooleanMethodA () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#9  0x00007efde0380d48 in ?? ()
   from /home/user/.javacpp/cache/java-sdk-samples-1.0-SNAPSHOT-jar-with-dependencies.jar/com/mycompany/myproject2/linux-x86_64/libjnimyproject.so
#10 0x00007efde03c09bc in ?? ()
#0  0x00007efef0bb88af in raise () from /lib64/libc.so.6
#1  0x00007efef0bba4aa in abort () from /lib64/libc.so.6
#2  0x00007efef0417ee9 in os::abort(bool) () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#3  0x00007efef063f03a in VMError::report_and_die() () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#4  0x00007efef0422095 in JVM_handle_linux_signal () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#5  0x00007efef04150a8 in signalHandler(int, siginfo_t*, void*) () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#6  <signal handler called>
#7  0x00007efef01dc4bf in jni_invoke_nonstatic(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*) [clone .constprop.235] ()
   from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#8  0x00007efef01e66aa in jni_CallBooleanMethodA () from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.1.centos7.x86_64/jre/lib/amd64/server/libjvm.so
#9  0x00007efde0380d48 in ?? ()
   from /home/user/.javacpp/cache/java-sdk-samples-1.0-SNAPSHOT-jar-with-dependencies.jar/com/mycompany/myproject2/linux-x86_64/libjnimyproject.so
#10 0x00007efde03c09bc in ?? ()
Stack: [0x00007efdd9ed8000,0x00007efdd9fd9000],  sp=0x00007efdd9fd6e00,  free space=1019k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x7034bf]  jni_invoke_nonstatic(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*) [clone .constprop.235]+0x27f
V  [libjvm.so+0x70d6aa]  jni_CallBooleanMethodA+0xfa
C  [libjnimyproject.so+0xafd48]

The generated jni code contains static callback array, which seems not to be protected by lock or synchronizes with proper memory order. I do not know if that's ok. (Besides, I do not see usage of rptr->ptr in operator()(uint64_t arg0))

static JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_instances[10];

JNIEXPORT void JNICALL Java_com_mycompany_myproject2_presets_myproject_00024FilterFunction_allocate(JNIEnv* env, jobject obj) {
    obj = env->NewWeakGlobalRef(obj);
    if (obj == NULL) {
        JavaCPP_log("Error creating global reference of com.mycompany.myproject2.presets.myproject.FilterFunction instance for callback.");
        return;
    }
    JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction* rptr = new (std::nothrow) JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction;
    if (rptr != NULL) {
        rptr->obj = obj;
        JavaCPP_initPointer(env, obj, rptr, 1, rptr, &JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_deallocate);
        for (int i = 0; i < 10; i++) {
            if (JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_instances[i].obj == NULL) {
                rptr->ptr = JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_allocate_callbacks[i];
                JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_instances[i] = *rptr;
                break;
            }
        }
    }
}

struct JavaCPP_hidden JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction {
    JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction() : ptr(NULL), obj(NULL) { }
    unsigned char operator()(uint64_t arg0);
    unsigned char (*ptr)(uint64_t arg0);
    jobject obj; static jmethodID mid;
};


unsigned char JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction::operator()(uint64_t arg0) {
    jboolean rarg = 0;
    JNIEnv* env;
    bool attached = JavaCPP_getEnv(&env);
    if (env == NULL) {
        goto end;
    }
{
    jvalue args[1];
    args[0].j = (jlong)arg0;
    if (obj == NULL) {
        obj = JavaCPP_createPointer(env, 120);
        obj = obj == NULL ? NULL : env->NewGlobalRef(obj);
        if (obj == NULL) {
            JavaCPP_log("Error creating global reference of com.mycompany.myproject2.presets.myproject.FilterFunction instance for callback.");
        } else {
            env->SetLongField(obj, JavaCPP_addressFID, ptr_to_jlong(this));
        }
        for (int i = 0; i < 10; i++) {
            if (this == &JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_instances[i]) {
                ptr = JavaCPP_com_mycompany_myproject2_presets_myproject_00024FilterFunction_allocate_callbacks[i];
                break;
            }
        }
    }
    if (mid == NULL) {
        mid = JavaCPP_getMethodID(env, 120, "call", "(J)Z");
    }
    if (obj == NULL) {
        JavaCPP_log("Function pointer object is NULL in callback for com.mycompany.myproject2.presets.myproject.FilterFunction.");
    } else if (mid == NULL) {
        JavaCPP_log("Error getting method ID of function caller \"public native boolean com.mycompany.myproject2.presets.myproject$FilterFunction.call(long)\" for callback.");
    } else {
        rarg = env->CallBooleanMethodA(obj, mid, args);
    }
}
end:
    JavaCPP_detach(attached);
    return rarg;
}

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4