Skip to Main Content

Java HotSpot Virtual Machine

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Accessing static JVM through C++ object shared across threads

843829Nov 24 2008 — edited Dec 16 2008
I have been fighting what I have narrowed down to a threading issue for a few days now... Any insights would be appreciated.

Setup: Solaris 10 - Java 1.6

I have created a C++ class (we'll call it JniHandler) that acts as an interface between C++ and a Java XCP API. When a JniHandler is instantiated, it checks for an existing JVM: If the JVM does not exist, it creates it and stores it as a private static member of the class. The JniHandler has a JNUtil_GetEnv function that is used to get the JNIEnv* pointer. The JNUtil_GetEnv function utilizes JNI's GetEnv function to determine if the currently executing thread is attached to the JVM and, if it is not, it calls the JNI AttachCurrentThread function to attach the thread.

In a C++ "driver" I instantiate a JniHandler, which in turn creates a JVM. I then pass a pointer to the JNI handler as an argument to the constructor of another class (we'll call it WorkerClass). WorkerClass spawns a pthread which uses the pointer to the JniHandler it received to call the corresponding native function. The native function begins by calling the JNUtil_GetEnv function to get the JNIEnv* pointer. The JNUtil_GetEnv function determines that the thread is not attached to the JVM and calls AttachCurrentThread. This produces a segmentation fault (SIGSEGV... Problematic frame: libjvm.so).

In case that doesn't make sense, here is the basic idea in code:
//Java XCP API
public XcpApi
{
   public static doSomethingInJava(void);
}

//C++ JniHandler
class JniHandler
{
   public:
      JniHandler();
      bool doSomething(void)

   private:
      static JavaVM* jvm_;

      bool JNUtil_GetEnv(void)
}

// allocate storage fro static class member variables
JniHandler::jvm_;

JniHandler::JniHandler()
{
   jsize numExistingJVMs = 0;
   jint jniCallResult;
   JNIEnv *env;

   jniCallResult = JNI_GetCreatedJavaVMs(&jvm_, 1, &numExistingJVMs);

   if (NULL != jvm_ && JNI_OK == jniCallResult && numExistingJVMs > 0)
   {
      //code to attach thread to existing JVM
   }
   else
   {
      //code to create JVM
   }
}

JNIEnv* JNUtil_GetEnv(void)
{
   JNIEnv* env = NULL;
   jint jniCallResult;

   if (NULL != jvm_)
   {
      jniCallResult = jvm_GetEnv((void**) &env, JNI_VERSION_1_6);
   
      switch (jniCallResult)
      {
         case JNI_EVERSION:
            // code to output version error
            break;
  
         case JNI_EDETACHED:

            jniCallResult = jvm_->AttachCurrentThread((void**) env, NULL);

            if (JNI_OK != jniCallResult)
            {
               //output error message
            }
 
            break;

         case JNI_OK:
 
            // Do nothing -- successfully obtained JNIEnv* pointer
            break;
      }
   }
   else
   {
      //output error message indicated jvm_ is NULL
   }

   return (env);
}

bool doSomething(void)
{
   bool success;
   JNIEnv* env = JNUtil_GetEnv();

   //Code to make JNI call to doSomethingInJava

   return (success);
}

class WorkerClass
{
   public:
      WorkerClass(JniHandler* aJniHandler);
      bool callDoSomethingFromAnotherThread(void);

   private:
      JniHandler* jniHandler_;
}

WorkerClass::WorkerClass(JniHandler* aJniHandler)
{
   jniHandler_ = aJniHandler;

   //code to spawn off a new pthread
}

bool WorkerClass::doSomethingFromAnotherThread(void)
{
   jniHandler_->doSomething();

   //return bool indication whether function call was successful
}

// C++ Driver app

int main(void)
{
   // This call successfully creates a JVM
   JniHandler* handler = new JniHandler();

   // At this point, from this context, handler->doSomething will execute successfully

   WorkerClass* worker = new WorkerClass(handler);

   // This call results in a segmentation fault when JNUtil_GetEnv() calls jvm_->AttachCurrentThread
   worker->doSomethingFromAnotherThread();
}
I've obviously dummied this down quite a bit to make it easier to understand. Hopefully I haven't left anything out. In lay mans terms, I can make any JNI call that I want through the JniHandler when I access it from the thread in which the JniHandler was created, but when I access the JniHandler from another thread, calling AttachCurrentThread results in a segmentation fault.

Any help is appreciated. Thanks in advance!

Any thought
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jan 13 2009
Added on Nov 24 2008
17 comments
959 views