Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Test and Performance Tools Platform (TPTP) » jni calls from a c++ tptp agent crashes vm
jni calls from a c++ tptp agent crashes vm [message #105147] Mon, 16 July 2007 20:21 Go to next message
Eclipse User
Originally posted by: natashads.gmail.com

Hi All,
This is a bizzare problem I'm encountering. I've written a dual tptp/jvm
agent in the old framework. The JVM_Onload method of the agent waits for
the vm to complete initialization before attempting to register the agent
with the agent controller. After some unspecified amount of time, the
agent receives a command and tries to carry out some jni function calls,
specifically, reading a system property from the vm it is running in.
This seems to be problematic: every vm I've tested on crashes with an
Access violation error at one of the FindClass or GetStaticMethodID
methods, both functions defined by JNI.. I've tested on windows with IBM
1.5 and Sun 1.4 and 1.5. Oddly enough, everything seems to work fine on
an IBM 1.4 JVM, some of the time. I have written a simple agent that has
the same problem, and the full source is below:

To try sending an arbitrary agent a command, you can use the sample
client posted at https://bugs.eclipse.org/bugs/show_bug.cgi?id=187891 and
add the following lines after the attach is complete:
CustomCommand customCommand = new CustomCommand();
customCommand.setData("somecommand");
agent.invokeCustomCommand(customCommand);



Compile flags:
JDK_HOME = D:\ibm_java5_sr5
RAC_LIB_DIR = D:\agnt_ctrl_410\lib
INCLUDES = -I D:\agnt_ctrl_410\include\ -I "C:\Program Files\Microsoft
Visual Studio .NET 2003\Vc7\PlatformSDK\Include" -I .
-I$(JDK_HOME)\include -I$(JDK_HOME)\include\win32
LINKOPTS = kernel32.lib $(RAC_LIB_DIR)\hcbnd.lib
$(RAC_LIB_DIR)\hcclco.lib $(RAC_LIB_DIR)\hccldt.lib
$(RAC_LIB_DIR)\hccls.lib $(RAC_LIB_DIR)\hcclsm.lib
$(RAC_LIB_DIR)\hcjbnd.lib
DEPS = sampleTPTPAgent.cpp
all: sampleTPTPAgent.dll

sampleTPTPAgent.dll: $(DEPS)
cl -LD -MD $(LINKOPTS) -Zi $(INCLUDES) /D"NO_INLINE"
/D"__TOS_WIN__" /Wp64 /EHsc -Tp $(DEPS) -o sampleTPTPAgent.dll


#include "sampleTPTPAgent.h"
static JNIEnv *env = NULL;
static JVMPI_Interface *jvmpi_interface = NULL;
static RA_AGENT_HANDLE handle = NULL;


extern "C" {
JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *vm, char *options, void
*reserved) {

int result = JNI_OK;
//Setup the JNI env ptr
result = vm->GetEnv((void **)&env, JNI_VERSION_1_2);

if (result != JNI_OK) {
printf("Error occurred getting JNI environment, return code %d\n",
result);
result = JNI_ERR;
} else {

// get jvmpi interface pointer
if ((vm->GetEnv((void **)&jvmpi_interface, JVMPI_VERSION_1_2)) < 0) {
fprintf(stderr, "error initializing jvmpi");
result = JNI_ERR;
} else {

jvmpi_interface->NotifyEvent = notifyEvent;

// register for jvm initialization notification so that we can
// create a thread to register with the AC
jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_INIT_DONE, NULL);

}
}
return result;
}
}




void notifyEvent(JVMPI_Event *event) {
switch(event->event_type) {
case JVMPI_EVENT_JVM_INIT_DONE:
jvmpi_interface->CreateSystemThread("Register thread",
JVMPI_NORMAL_PRIORITY, registerAgent);
break;
}
}



void getUserDir(void* param){

char *dir = NULL;
jclass cls;
jstring key;
jobject obj;
jstring value;
jmethodID mID;
jsize stringLength;

cls = env->FindClass("java/lang/System");
if (cls != NULL && cls != 0) {
mID = env->GetStaticMethodID(cls, "getProperty",
"(Ljava/lang/String;)Ljava/lang/String;");
if (mID != NULL) {
key = env->NewStringUTF("user.dir";
obj = env->CallStaticObjectMethod(cls, mID, key);
if (obj != NULL) {
value = (jstring) obj;
const char *str = env->GetStringUTFChars(value, 0);
stringLength = env->GetStringUTFLength(value);
dir = (char *) malloc(sizeof(char) * stringLength);
strcpy (dir, str);
env->ReleaseStringUTFChars(value, str);

}
}
}

}

if (dir != NULL) {
fprintf(stderr, "dir: %s\n", dir); //Pring out working direcotry
}
}

void incomingCommand(ra_command_t *command) {
switch (command->tag) {
case RA_CUSTOM_COMMAND:
getUserDir(NULL); //try getting the "user.dir" system property
break;
}
}

/**Registers the agent with the agent controller */
void registerAgent(void *param) {
TID *tid;
//initialize rac libraries
handle = ra_initializeBindings("sample.tptp.agent", "Profiler",
incomingCommand, FALSE);
if (handle == NULL) {
fprintf(stderr, "Could not initialize agent\n");
} else {
fprintf(stderr, "agent intialized\n");
tid = ra_startListener(handle, 0 );
if (tid != NULL) {
fprintf(stderr, "agent ready to receive commands!\n");
}
}
fflush(stderr);
}


void notifyEvent(JVMPI_Event *event) {
switch(event->event_type) {
case JVMPI_EVENT_JVM_INIT_DONE:
jvmpi_interface->CreateSystemThread("Register thread",
JVMPI_NORMAL_PRIORITY, registerAgent);
break;
case JVMPI_EVENT_JVM_SHUT_DOWN:
if (handle != NULL && handle->registered) {
ra_stopListener(handle);
ra_finalizeBindings(handle);
handle = NULL;
}
break;
}
}
Re: jni calls from a c++ tptp agent crashes vm [message #105260 is a reply to message #105147] Tue, 17 July 2007 14:16 Go to previous messageGo to next message
Asaf Yaffe is currently offline Asaf Yaffe
Messages: 333
Registered: July 2009
Senior Member
Hi,

I can think of two reasons why the code crashes:
1. The thread which processes the custom Agent command is not attached
to the JVM.

2. (partly related to the previous problem): an incorrect use of the JNI
environment pointer. JNIEnv pointers are thread-dependent, and cannot be
shared between multiple threads (you're storing it in a static
variable). The "env" variable is initialized to the JNIEnv of the thread
which loads your agent. Most likely, this is not the thread on which the
"custom command" handler is called. Hence a crash (I am actually
surprised this is working on some JVMs).

Your "agent command" handler must test whether the current (calling)
thread is attached to the JVM (and attach it if it is not), and then
obtain its correct JNI environment.

HTH,
Asaf

--
Asaf Yaffe
Eclipse TPTP Committer, JVMTI Profiler
Re: jni calls from a c++ tptp agent crashes vm [message #105349 is a reply to message #105260] Tue, 17 July 2007 19:36 Go to previous message
Natasha D'Silva is currently offline Natasha D'Silva
Messages: 25
Registered: July 2009
Junior Member
Thank you so much! I knew I was doing something wrong!
It works now on all vms, I store the JavaVM pointer and re-use it to attach
the current thread in the incomingCommand() method. I scoured the doc and
can't find anything to suggest I shouldn't do that.

I really appreciate your help, I was quite stumped!
Thanks again,
Natasha D'Silva


"Asaf Yaffe" <asaf.yaffe@intel.com> wrote in message
news:f7ij0d$th3$1@build.eclipse.org...
> Hi,
>
> I can think of two reasons why the code crashes:
> 1. The thread which processes the custom Agent command is not attached to
> the JVM.
>
> 2. (partly related to the previous problem): an incorrect use of the JNI
> environment pointer. JNIEnv pointers are thread-dependent, and cannot be
> shared between multiple threads (you're storing it in a static variable).
> The "env" variable is initialized to the JNIEnv of the thread which loads
> your agent. Most likely, this is not the thread on which the "custom
> command" handler is called. Hence a crash (I am actually surprised this is
> working on some JVMs).
>
> Your "agent command" handler must test whether the current (calling)
> thread is attached to the JVM (and attach it if it is not), and then
> obtain its correct JNI environment.
>
> HTH,
> Asaf
>
> --
> Asaf Yaffe
> Eclipse TPTP Committer, JVMTI Profiler
Previous Topic:[AGR] AGR hangs when widgetReg.xml contains an error
Next Topic:Agent Controller Vs Webserver
Goto Forum:
  


Current Time: Thu Oct 23 05:27:02 GMT 2014

Powered by FUDForum. Page generated in 0.01749 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software