#java-native-interface #systemc
#java-native-interface #systemc
Вопрос:
При использовании JNI в SystemC я сталкиваюсь с очень странной проблемой, которую я не могу объяснить сам.
Просто некоторая информация о моей используемой среде: в настоящее время я разрабатываю ubuntu 12.04 с установленными openjdk-6 и openjdk-7. Проблема воспроизводится с обоими jdk!
Наличие этого основного метода:
#include "tlm.h"
#include "SystemCWrapper.h"
int sc_main(int argc, char *argv[]) {
SystemCWrapper wrapper("test");
std::cout << "############ Before ############" << std::endl;
wrapper.run();
std::cout << "############ SC-START ############" << std::endl;
sc_core::sc_start();
std::cout << "############ After ############" << std::endl;
wrapper.run();
return 0;
}
и следующая реализация SystemCWrapper:
#include "SystemCWrapper.h"
#include <jni.h>
#include <iostream>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
SC_HAS_PROCESS( SystemCWrapper );
using std::cout;
using std::cerr;
using std::endl;
static JavaVM * createJavaVM () {
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[2];
options[0].optionString = const_cast<char*>("-Djava.class.path=HelloWorld.jar");
options[1].optionString = const_cast<char*>("-verbose:jni");
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1; // NOTE: set to 2 for more verbose jni information
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface pointer in env */
JNI_CreateJavaVM(amp;jvm, (void**) amp;env, amp;vm_args);
return jvm;
}
SystemCWrapper::SystemCWrapper(sc_core::sc_module_name nam) : sc_module(nam), jvm(NULL){
SC_THREAD(run); // Thread to run the ISS
// setup the JNI
jvm = createJavaVM();
}
SystemCWrapper::~SystemCWrapper() {
}
void SystemCWrapper::run() {
// Print general information
cout << "Hello SystemC (PID: " << getpid() << ", PTID: " << pthread_self() << ", LTID: " << syscall(SYS_gettid) << ")" << endl;
JNIEnv* env;
int ret = jvm->GetEnv((void**)amp;env, JNI_VERSION_1_6);
if(ret == JNI_OK) {
cout << "Retrieve successful." << endl;
} else if(ret == JNI_EDETACHED){
cerr << "Environment is detached." << endl;
} else {
cerr << "Retrieving environment failed! (" << ret << ")" << endl;
}
jclass clazz = env->FindClass("JavaProgram");
if(clazz == NULL) {
cerr << "Class not found" << endl;
return;
}
jmethodID mConstr = env->GetMethodID(clazz, "<init>", "()V");
if(mConstr == NULL) {
cerr << "Constructor not found" << endl;
return;
}
jmethodID mRun = env->GetMethodID(clazz, "run", "()I");
if(mRun == NULL) {
cerr << "Run method not found" << endl;
return;
}
jobject obj = env->NewObject(clazz, mConstr);
if(obj == NULL) {
cerr << "Object was not created!" << endl;
return;
}
int result = env->CallIntMethod(obj, mRun);
if(result == 0) {
cerr << "Run should never return 0!" << endl;
return;
}
}
Приводит к следующему консольному выводу (Java-программа выводит только «Привет, Java!», Если вызывается):
$ ./build/bin/jnitest
SystemC 2.3.1-Accellera --- Jun 6 2014 13:36:39
Copyright (c) 1996-2014 by all Contributors,
ALL RIGHTS RESERVED
############ Before ############
Hello SystemC (PID: 5660, PTID: 140661929555776, LTID: 5660)
Retrieve successful.
Hello Java!
############ SC-START ############
Hello SystemC (PID: 5660, PTID: 140661929555776, LTID: 5660)
Retrieve successful.
Object was not created!
############ After ############
Hello SystemC (PID: 5660, PTID: 140661929555776, LTID: 5660)
Retrieve successful.
Hello Java!
Похоже, что метод SystemC sc_core::sc_start();
делает что-то, что каждый вызов JNI не «передается» в Java.
Я попробовал некоторые настройки, но даже если я подключу текущий поток к jvm, ничего не изменится (как видно, идентификаторы потоков даже остаются неизменными).
Есть предложения? Пожалуйста, дайте мне знать, если требуется дополнительная информация.
Комментарии:
1. Что вы пытаетесь сделать на самом деле? Связывание SystemC и виртуальной машины Java создает довольно странную вещь, которую нужно пытаться сделать.
2. Я согласен, что на первый взгляд это выглядит странно, но в нашей текущей ситуации у нас есть симулятор набора команд, реализованный на Java. Теперь мы хотим интегрировать его в платформу моделирования платформы, основанную на SystemC / TLM. В принципе, мы хотим достичь того же, что и в embecosm.com/appnotes/ean1/ean1-tlm2-or1ksim-2.0.html , но вместо того, чтобы создавать оболочку SystemC / TLM для симулятора на основе C, мы хотим обернуть наш java-симулятор с помощью JNI.
3. Размер стека в контексте SC_THREAD? Вы запускаете что-то гораздо более тяжелое, чем стандартное.
4. Я пытался увеличить размер стека, используя
set_stack_size(size_t size)
, но это не помогло. Я также скорректировал код, чтобы вызывать только статический метод (вместо создания объекта и вызова метода для него), но это тоже не помогло. Но я заметил, что в коде Java возникает исключение, поэтому я изменил код на «открытый класс JavaProgram {public static int run() { return -1; } }», но исключение все равно выдается. Печатая исключение после sc start() с помощью env-> ExceptionDescribe(), я получаю исключение StackOverflow при возврате -1. Может быть, это связано с моделью sc_thread?
Ответ №1:
После расследования и большого этапа проб и ошибок я пришел к выводу, что это не очень просто решить самостоятельно. По этой причине я создал pthread, который обрабатывает вызовы JNI вне SC_THREAD .
Я предполагаю, что проблема заключается в том, что библиотека QuickThreads под systemc не может использоваться в сочетании с JNI. Я ничего не нашел в этой области, но, возможно, я не очень хорошо искал.
Я также мог бы перекомпилировать systemc, используя pthreads вместо QuickThreads, но поскольку мое решение должно работать в обеих конфигурациях, это не вариант для меня.
Наконец, вот сокращенный код, который помог мне избавиться от моих страданий.
static JNIEnv* getJniEnv(JavaVM* jvm) {
JNIEnv* env = NULL;
int i = jvm->GetEnv((void**) amp;env, JNI_VERSION_1_6);
if (i == JNI_EDETACHED) {
int ret = jvm->AttachCurrentThreadAsDaemon((void **) amp;env, NULL);
if ( ret != 0) {
cerr << "Failed to attach thread to jni (" << ret << ")!n";
}
} else if(i != JNI_OK) {
cerr << "Failed retrieving jni environment!n";
}
if(env == NULL) {
cerr << "Pointer to JNIEnv is NULL!n";
}
return env;
}
SystemCWrapper::SystemCWrapper(sc_core::sc_module_name nam) : sc_module(nam), jvm(NULL) {
SC_THREAD(spawnAndRun); // Thread to run the ISS
// setup the JNI
jvm = createJavaVM();
}
SystemCWrapper::~SystemCWrapper() {}
static void * doStart(void * data) {
SystemCWrapper* wrapper = (SystemCWrapper*)data;
wrapper->run();
return NULL;
}
void SystemCWrapper::spawnAndRun() {
pthread_t t;
void * ret;
pthread_create(amp;t, NULL, doStart, (void*)this);
pthread_join(t, amp;ret);
}
void SystemCWrapper::run() {
// Print general information
cout << "Hello SystemC (PID: " << getpid() << ", PTID: " << pthread_self() << ", LTID: " << syscall(SYS_gettid) << ")" << endl;
JNIEnv* env = getJniEnv(jvm);
if(env == NULL)
return;
jclass clazz = env->FindClass("JavaProgram");
// ... same code as above ... //
}
@Ifor большое спасибо за ваш отзыв!!!