使用JNI使用C计时器库接口java [英] interface java with C timer library using JNI

查看:113
本文介绍了使用JNI使用C计时器库接口java的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力让这个简单的例子起作用:

I'm trying to make this simple example work:

import java.io.*;

public class Timer {
    public static void main(String[] args) {
        setTimer(new Runnable() {
                public void run() {
                    System.out.println("tick");
                }
            },
            1000 /* msecs */
        );
        while (true) ;
    }

    native public static void setTimer(Runnable r, int msecs);

    static {
        System.loadLibrary("timer");
    }
}

代码很简单。使用 SIGALRM setitimer setTimer >。示例应该每秒打印 tick

Code is straightforward. Program setTimer in JNI/C/Linux using SIGALRM and setitimer. Example should print tick every second.

JNI库被编程为:

#include <signal.h>
#include <sys/time.h>

#include "Timer.h"
#include "error.h"

static JNIEnv *genv;
static jobject gobj;

void handler(int s) {
    jclass cls = (*genv)->GetObjectClass(genv, gobj);
    jmethodID mid = (*genv)->GetMethodID(genv, cls, "run", "()V");
    (*genv)->CallVoidMethod(genv, gobj, mid);
}

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);

    genv = env;
    gobj = 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)
        SysError("setTimer: sigaction, setitimer: couldn't init timer");
}

我正在使用信号链库,以免信号干扰JVM:

I'm using signal-chaining library in order not to have signal interference with the JVM:

LD_LIBRARY_PATH=. LD_PRELOAD=/usr/lib/jvm/java-6-openjdk/jre/lib/i386/libjsig.so java Timer

SIGALRM第一次使用以下消息触发JMV段错误:

The first time SIGALRM fires JMV segfaults with a message:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00e9531c, pid=5742, tid=3077924544
#
...

为什么?

推荐答案

问题是无效的genv和gobj。 genv和gobj在变量集和离开Java_Timer_setTimer函数之间有效。您可以从当前的jvm获取env *并将obj设置为global ref。我定义了新的变量:

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;

在Java_Timer_setTimer中:

In Java_Timer_setTimer:

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

在句柄中,使用jvm附加当前线程并调用回调:

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.
    }
}

这篇关于使用JNI使用C计时器库接口java的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆