开发者

JVMTI agent crashes

开发者 https://www.devze.com 2023-04-04 17:22 出处:网络
I\'m working on implementation of eraser data-race detection algorithm as JVMTI agent. When I try to run some example inputs to test my code, the JVM crashes, with dumps like the following (may show o

I'm working on implementation of eraser data-race detection algorithm as JVMTI agent. When I try to run some example inputs to test my code, the JVM crashes, with dumps like the following (may show other stack traces for the same error as well):

FATAL ERROR in native method: Using JNIEnv in the wrong thread at Proxy.monitor_enter_(Native Method) at Proxy.monitor_enter(Proxy.java:30) at ex1.LifeThreads.setNeighborThreadChange(LifeThreads.java:36) at ex1.LifeThreads.neighbor(LifeThreads.java:425) at ex1.LifeThreads.standardItr(LifeThreads.java:321) at ex1.LifeThreads.run(LifeThreads.java:462)

(This kind of post-mortem trace is possible to obtain with -Xcheck:jni option to Sun JVM)

In the code I do the same kind of instrumentation as shown in various JDK samples (heapViewer, heapTracker, etc. via some proxy java class with native methods). Proxy.monitor_enter_ native method is invoked after each monitorenter instruction.

This is the code for monitor_enter_:

void native_monitor_exit(JNIEnv *jni, jclass klass, jthread thread_id, jobject obj)
{
    scoped_lock( agent::instance()->jvmti(), agent::instance()->monitor_ );
        if( agent::instance()->death_active_)
                return;

    std::string name = agent::instance()->thread_name( thread_id );
        thread_t* thread = get_thread( thread_id );
        if( thread == 0 )
开发者_StackOverflow社区            return;
        jobject global_ref = agent::instance()->jni()->NewGlobalRef( obj );
        if( global_ref == 0 )
                fatal_error("Out of memory while trying to create new global ref.");

    logger::instance()->level(1) << "MONITOR ENTER"
                << "\n\t" << "jthread name= " << name
                << "\n\t" << "thread_t= " << thread << " " << *thread
                << "\n\t" << "monitor gl= " << global_ref
                << std::endl;

        thread->lock( lock(global_ref) );
}

, where scoped_lock basically is a scoped lock for JVMTI Raw Monitor enter/exit, thread_t is just a struct wrapping some std::vector, where instance of class lock (that itself merely wraps jobject global reference global_ref) is stored, when thread->lock( lock(global_ref)) is invoked.

JVMTI env. is cached globally in agent singleton, whereas, JNI env, which is thread-local is reloaded each time prior to its use (which is not that efficient, but for now I do not care), as shown below:

    JNIEnv* jni()
{
    jint res;
    JNIEnv* env = 0;
    res = jvm()->GetEnv( (void**)&env, JNI_VERSION_1_2 );
    if( res == JNI_EDETACHED )
    {
        res = jvm()->AttachCurrentThread( (void **)&env, 0 );
        if( res != JNI_OK || env == 0 )
            fatal_error( "ERROR: Unable to create JNIEnv by attach, error=%d\n", res );
    }
        else if( res != JNI_OK || env == 0 )
        fatal_error( "ERROR: Unable to create JNIEnv, error=%d\n", res );
    }
    return env;
}


You should be using jni parameter which passed to your native_monitor_exit method, rather than looking it up in your jni() method, it is the jni environment you should be using when a method is called from Java.

0

精彩评论

暂无评论...
验证码 换一张
取 消