When using JNI within SystemC I face a very strange issue I can't explain myself.
Just some information on my used environment: I am currently developing on a 12.04 ubuntu with openjdk-6 and openjdk-7 installed. The issue reproduces with both jdks!
Having this main method:
#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;
}
and the following implementation of the 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(&jvm, (void**) &env, &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**)&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;
}
}
Results into the following console output (Java program only outputs "Hello Java!", if invoked):
$ ./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!
It seems that the SystemC method sc_core::sc_start();
does something that each JNI invocation is not "passed through" to Java.
I've tried some tweaks but even if I attach the current thread to the jvm nothing changes (as one can see the thread ids even remain the same).
Any suggestions? Please let me know If more information is required.