interface java with C timer library using JNI

前端 未结 1 1891
一向
一向 2021-01-06 17:00

I\'m trying to make this simple example work:

import java.io.*;

public class Timer {
    public static void main(String[] args) {
        setTimer(new Runna         


        
相关标签:
1条回答
  • 2021-01-06 17:09

    The problem is the invalid genv and gobj. genv and gobj are valid between variable set and leaving Java_Timer_setTimer function. You can get env* from the current jvm and make the obj to global ref. I define the new variables:

    static JavaVM *jvm = NULL;
    static jobject callback = NULL;
    

    In Java_Timer_setTimer:

    /* find the current jvm */
    (*env)->GetJavaVM(env, &jvm);
    /* upgrade callback to global ref */
    callback = (*env)->NewGlobalRef(env, obj);
    

    In handle, use jvm to attach current thread and invoke callback:

    void handler(int s) {
        if(jvm == NULL)
            return ;
        if(callback == NULL)
            return ;
    
        JNIEnv *env = NULL;
        jint res;
        res = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
        if(res < 0)
        {
            fprintf(stderr, "Attach VM Thread failed\n");
            return ;
        }
    
        jclass cls = (*env)->GetObjectClass(env, callback);
        jmethodID mid = (*env)->GetMethodID(env, cls, "run", "()V");
        (*env)->CallVoidMethod(env, callback, mid);
        (*jvm)->DetachCurrentThread(jvm);
    }
    

    Finally, we make it runnable:

    qrtt1@qrtt1-VirtualBox:/media/sf_VBoxSharedFolder/0Lab$ java -Djava.library.path=. -classpath bin Timer
    tick Tue Jul 24 13:01:54 CST 2012
    tick Tue Jul 24 13:01:55 CST 2012
    tick Tue Jul 24 13:01:56 CST 2012
    tick Tue Jul 24 13:01:57 CST 2012
    tick Tue Jul 24 13:01:58 CST 2012
    

    The completed source code are:

    #include "Timer.h"
    #include <jni.h>
    #include <signal.h>
    #include <sys/time.h>
    #include <stdio.h>
    
    
    static JavaVM *jvm = NULL;
    static jobject callback = NULL;
    
    void handler(int s) {
        if(jvm == NULL)
            return ;
        if(callback == NULL)
            return ;
    
        JNIEnv *env = NULL;
        jint res;
        res = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
        if(res < 0)
        {
            fprintf(stderr, "Attach VM Thread failed\n");
            return ;
        }
    
        jclass cls = (*env)->GetObjectClass(env, callback);
        jmethodID mid = (*env)->GetMethodID(env, cls, "run", "()V");
        (*env)->CallVoidMethod(env, callback, mid);
        (*jvm)->DetachCurrentThread(jvm);
    }
    
    /*
     * Class:     Timer
     * Method:    setTimer
     * Signature: (Ljava/lang/Runnable;I)V
     */
    JNIEXPORT void JNICALL Java_Timer_setTimer
      (JNIEnv *env, jclass cls, jobject obj, jint msecs)
    {
    
        struct sigaction sa;
        struct itimerval it;
    
        sa.sa_flags = SA_RESTART;
        sigemptyset (&sa.sa_mask);
    
        /* find the current jvm */
        (*env)->GetJavaVM(env, &jvm);
        /* upgrade callback to global ref */
        callback = (*env)->NewGlobalRef(env, obj);
    
        sa.sa_handler = handler;
        it.it_interval.tv_sec = msecs/1000;
        it.it_interval.tv_usec = (msecs%1000)*1000;
        it.it_value = it.it_interval;
    
        if (sigaction (SIGALRM/*PROF*/, &sa, NULL) == -1
                || setitimer (ITIMER_REAL/*PROF*/, &it, NULL) == -1)
        {
            // error.
        }
    }
    
    0 讨论(0)
提交回复
热议问题