Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > trouble passing float array from C to java method

Reply
Thread Tools

trouble passing float array from C to java method

 
 
Arash Nikkar
Guest
Posts: n/a
 
      02-16-2007
I have a float array, and I am trying to pass it to a java method, but
it craps out during the call to pass the array. Anyone have any ideas?

Here is the header for the java method:

public void addPoints(final float[] scopePoints)

and here is the C++ reference to this method:

addPoints = jenv->GetMethodID(myClass, "addPoints", "([F)V");

lastly, here is the code in question (the printMsg function is just a
helper function which calls a println method in my java class). Also,
SampleData is defined as such: float SampleData[3072];

jfloat realGraph[3000];
printMsg("created jint array\n");
for (i=0;i<3000;i++)
{
realGraph[i] = SampleData[i];
}

printMsg("copied array\n");

jfloatArray returnArray = jenv->NewFloatArray(3000);
printMsg("created java jint array\n");

jenv->SetFloatArrayRegion(returnArray,
0,3000,realGraph);
printMsg("transfered data into java array\n");

jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
WHERE IT FAILS!!!
printMsg("passed the array\n");


when i run the code, all of the print messages come through except the
last one. I also added loops which printed out the contents of each
array (SampleData, realGraph, & returnArray), and they all contain the
correct contents.

Any help is appreciated

 
Reply With Quote
 
 
 
 
Chris Uppal
Guest
Posts: n/a
 
      02-16-2007
Arash Nikkar wrote:

> jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
> WHERE IT FAILS!!!
> printMsg("passed the array\n");


What is the value of jobj at this point ? Your code looks OK to me, so I
suspect that jobj might not be properly set up.

In general, it's a very bad idea to call JNI functions without checking for
errors. That call, or any of the preceeding JNI functions might have failed,
and once something has failed (thrown a Java exception which you haven't
checked for), nothing else will work. If you add error checking, then that
might help track down the problem.

Incidentally, I think an array of 3000 floats is a little large to be
allocating on the C stack; its not large enough that expect that it would
routinely cause problems, but not so small that I'd ignore it either.

-- chris


 
Reply With Quote
 
 
 
 
Arash Nikkar
Guest
Posts: n/a
 
      02-16-2007
On Feb 16, 11:01 am, "Chris Uppal" <(E-Mail Removed)-
THIS.org> wrote:
> Arash Nikkar wrote:
> > jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
> > WHERE IT FAILS!!!
> > printMsg("passed the array\n");

>
> What is the value of jobj at this point ? Your code looks OK to me, so I
> suspect that jobj might not be properly set up.
>
> In general, it's a very bad idea to call JNI functions without checking for
> errors. That call, or any of the preceeding JNI functions might have failed,
> and once something has failed (thrown a Java exception which you haven't
> checked for), nothing else will work. If you add error checking, then that
> might help track down the problem.
>
> Incidentally, I think an array of 3000 floats is a little large to be
> allocating on the C stack; its not large enough that expect that it would
> routinely cause problems, but not so small that I'd ignore it either.
>
> -- chris


Hi chris,

job is my jobject reference. For this application, the C code is
running in the background and calling my Java function when it gathers
a specific number of results.

I tried reducing the size of my array to 500, but I got the same
problem, the program crashed as it was sending the array to my java
function.

I dont quite understand what you mean by adding error checking. Im
assuming you mean in the c++ code...what type of error checking? could
you give me an example.

Lastly, Im pretty sure that my jenv and job objects are setup
correctly, as the printMsg uses them. Here is the code for my printMsg
method:

void printMsg(char *str) {
jstring myString = jenv->NewStringUTF(str);
jenv->CallVoidMethod(job, print, myString);
}

Thanks for all your help!

 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      02-17-2007
On Feb 16, 2:11 pm, "Arash Nikkar" <(E-Mail Removed)> wrote:
> On Feb 16, 11:01 am, "Chris Uppal" <(E-Mail Removed)-
>
>
>
> THIS.org> wrote:
> > Arash Nikkar wrote:
> > > jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
> > > WHERE IT FAILS!!!
> > > printMsg("passed the array\n");

>
> > What is the value of jobj at this point ? Your code looks OK to me, so I
> > suspect that jobj might not be properly set up.

>
> > In general, it's a very bad idea to call JNI functions without checking for
> > errors. That call, or any of the preceeding JNI functions might have failed,
> > and once something has failed (thrown a Java exception which you haven't
> > checked for), nothing else will work. If you add error checking, then that
> > might help track down the problem.

>
> > Incidentally, I think an array of 3000 floats is a little large to be
> > allocating on the C stack; its not large enough that expect that it would
> > routinely cause problems, but not so small that I'd ignore it either.

>
> > -- chris

>
> Hi chris,
>
> job is my jobject reference. For this application, the C code is
> running in the background and calling my Java function when it gathers
> a specific number of results.
>
> I tried reducing the size of my array to 500, but I got the same
> problem, the program crashed as it was sending the array to my java
> function.
>
> I dont quite understand what you mean by adding error checking. Im
> assuming you mean in the c++ code...what type of error checking? could
> you give me an example.
>
> Lastly, Im pretty sure that my jenv and job objects are setup
> correctly, as the printMsg uses them. Here is the code for my printMsg
> method:
>
> void printMsg(char *str) {
> jstring myString = jenv->NewStringUTF(str);
> jenv->CallVoidMethod(job, print, myString);
>
> }
>
> Thanks for all your help!



Does it crash, or simply never return? Could it be a problem in
addPoints?

 
Reply With Quote
 
Gordon Beaton
Guest
Posts: n/a
 
      02-17-2007
On 16 Feb 2007 14:11:35 -0800, Arash Nikkar wrote:
> Lastly, Im pretty sure that my jenv and job objects are setup
> correctly, as the printMsg uses them. Here is the code for my
> printMsg method:
>
> void printMsg(char *str) {
> jstring myString = jenv->NewStringUTF(str);
> jenv->CallVoidMethod(job, print, myString);
> }


Note that you should call DeleteLocalRef(myString) before returning
from this function.

If your C++ code is running in its own thread and producing objects
without returning to Java (*calling* Java is not suffucient), then you
must dispose of them when you're finished using them. Failing to do so
is a serious bug that could very well be the cause of your current
problem.

Consider bracketing the code in calls to PushLocalFrame() and
PopLocalFrame().

/gordon

--
[ don't email me support questions or followups ]
g o r d o n + n e w s @ b a l d e r 1 3 . s e
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      02-17-2007
Arash Nikkar wrote:

> > What is the value of jobj at this point ? Your code looks OK to me, so
> > I suspect that jobj might not be properly set up.


> job is my jobject reference. For this application, the C code is
> running in the background and calling my Java function when it gathers
> a specific number of results.


Just to check: the jobj is a global ref, or a local ref (jobject) from the
JNIEnv associated with your background thread ? If not then that might be your
problem.


> > In general, it's a very bad idea to call JNI functions without checking
> > for errors. That call, or any of the preceeding JNI functions might
> > have failed, and once something has failed (thrown a Java exception
> > which you haven't checked for), nothing else will work. If you add
> > error checking, then that might help track down the problem.


> I dont quite understand what you mean by adding error checking. Im
> assuming you mean in the c++ code...what type of error checking? could
> you give me an example.


After every call to JNI you should check for errors (there are, in fact, a few
JNI functions which have no way to fail, but they are in the minority -- if you
see JNI code without an error check, then you should wonder why it's missing).



> printMsg("created jint array\n");


Since you've said that printMsg() uses JNI, it should check for errors too (as
below).


> jfloatArray returnArray = jenv->NewFloatArray(3000);


This can fail. So you should check the returned value (it may be NULL). I'm
not certain, but I /think/ that if the returned value is not NULL then you are
not obliged to check for Java exceptions too. (I do anyway, myself, but that's
in automatically-generated code so it's easier always to check than to try to
spot the cases where a check can be skipped).


> jenv->SetFloatArrayRegion(returnArray,
> 0,3000,realGraph);


You'll have to check the spec to see whether this can potentially fail. I
don't /think/ so, but it's your responsibility to check the specification.


> jenv->CallVoidMethod(job, addPoints, returnArray);


This can fail by throwing a Java exception. The only way to check whether that
happened is one of ExceptionCheck() or ExceptionOcurred(). If it did then you
can clear it with ExceptionClear(). If you don't clear it then subsequent JNI
calls will fail. The helper function ExceptionDescribe() may also be useful
(but for the life of me, I can't remember whether it implicitly clears the
pending exception).


> void printMsg(char *str) {
> jstring myString = jenv->NewStringUTF(str);
> jenv->CallVoidMethod(job, print, myString);
> }



You should also do the same kind of messing around inside printMsg():
NewString() can fail, and CallVoidMethod() can throw exceptions. (And you
should release the jstring, as Gordon has already explained).


I know that all that checking is /extremely/ tedious, and messes up the code.
Unfortunately, it's necessary (which is one of the reasons I don't write JNI
code by hand...).


BTW, if you haven't already tried turning on the -Xcheck:jni option, then that
is probably worth the effort. NB: I have known it produce false positives
(complain about something that was perfectly OK, and abort when there was no
need) in one dot.dot release of JDK 1.5, but it is usually helpful (of course,
if it /doesn't/ complain then that doesn't imply that the code /is/ OK).

-- chris


 
Reply With Quote
 
Arash Nikkar
Guest
Posts: n/a
 
      02-20-2007
Thanks for all the replies, here are some answers:

I have made some progress (I believe I found the source of the
problem, but I cant figure it out just yet).

I added the Xcheck:jni runtime option, and I got the following:

FATAL ERROR in native method: Using JNIEnv in the wrong thread
at RealGraph.startScope(Native Method)
at RealGraph$2.run(RealGraph.java:134)
at java.lang.Thread.run(Thread.java:595)

Then I realized I was calling this method from within another Java
Thread (I didn't know this would have any type of effect). So I moved
the call outside of the thread (i.e. it would make my GUI hang, but
thats ok for now), but then I got this:

FATAL ERROR in native method: Wrong object class or methodID passed to
JNI call
at RealGraph.startScope(Native Method)
at RealGraph.main(RealGraph.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(Native MethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(De legatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.intellij.rt.execution.application.AppMain.main (AppMain.java:
90)

Some background on how I have things setup. When I first start my
application, I call an initialization method in my C++ class which
sets global environment variables for JENV, Jobject, and my method
pointers (i.e. addPoints, print), etc. I also do some checks there.

Then, when I am ready to start polling, I call the startScope method.
Here I only perform polling operations. I do not replace my
environment variables or method pointers. I did try this however, and
I got the same exception as the one above.


Lastly, for exception checking, will calls to ExceptionCheck() or
ExceptionOcurred() suffice, or should I check for null values as well?

thanks for all your help!

 
Reply With Quote
 
Gordon Beaton
Guest
Posts: n/a
 
      02-20-2007
On 20 Feb 2007 10:26:53 -0800, Arash Nikkar wrote:
> Some background on how I have things setup. When I first start my
> application, I call an initialization method in my C++ class which
> sets global environment variables for JENV, Jobject, and my method
> pointers (i.e. addPoints, print), etc. I also do some checks there.


Don't cache the JNIEnv!

Also, be careful when caching object references: it's only safe to
cache global references.

/gordon

--
[ don't email me support questions or followups ]
g o r d o n + n e w s @ b a l d e r 1 3 . s e
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      02-20-2007
Arash Nikkar wrote:

> Some background on how I have things setup. When I first start my
> application, I call an initialization method in my C++ class which
> sets global environment variables for JENV, Jobject, and my method
> pointers (i.e. addPoints, print), etc. I also do some checks there.


It OK to put methodIDs (method pointers) into global variables because they can
be used from any thread, but jobjects and JNIEnvs are completely tied to the
thread which created them and they must never be used from any other thread.

In JNI there are three possible scenarios.

1) (I include this case only for completeness since I don't think it applies to
you.) The application itself is in C (or similar), and uses JNI to invoke Java
code. In this case the C code will load and launch the JVM itself, and in
doing so will create a JNIEnv which is valid in, and only in, that OS thread.
Any jobjects (local references) which are created via that JNIEnv are also
valid on that thread (and only on that thread). Note that you must release
such references explicitly.

2) Your C code is invoked via a Java 'native' call. In that case the Java
runtime will supply a JNIEnv for you to use for the duration of that call.
That JNIEnv is not valid in any other call, nor in any other thread. Any
jobject (local reference) created during that call will be released when the
call returns back to Java code, so the jobject is invalid anywhere else too.

3) Your C code is running on a separate thread which the Java VM doesn't know
about. Unless you /tell/ the JVM about that thread then no JNIEnv or jobject
can validly be used from it. If you call the JNI function
AttachCurrentThread() or AttachCurrentThreadAsDemon(), that tells the JVM about
the thread from which it was called, and passes back a JNIEnv. The new JNIEnv
is valid for use on that thread, and only on that thread. Any jobjects (local
references) which are created via that JNIEnv are also valid on that thread
(and only on that thread). Note that you must release such references
explicitly.

If you need (as I think you do) to store a reference to a specific Java object,
and use that later from different places and threads, then you must convert it
to a "global reference" using NewGlobalRef(). Such a global reference is valid
in any thread. It must be released explicitly.

Incidentally, the JNI function GetEnv() can be used to retrieve the correct
JNIEnv to use it whatever context its called from (it'll return an error if
called from a thread which hasn't been attached by the JVM). That function is
(by design) very quick so it may be more convenient for you to use that instead
of global variables.


> Lastly, for exception checking, will calls to ExceptionCheck() or
> ExceptionOcurred() suffice, or should I check for null values as well?


You are asking about the call to NewFloatArray() ? If so then I believe that
either an exception check, or a NULL check, is adequate -- you don't need to do
both. That applies to all the array-creation methods.

In the more general case (not just array creation) where a JNI function returns
a jobject. I believe (but am not totally certain) that they always return NULL
if there is any problem, so you only have to do the exception check if you see
a NULL return. (Some of the functions can return NULL without it being an
indication of a problem, so you can't in general use an exception check
/instead/ of a NULL check). For instance calling this Java method, with
CallObjectMethod(), would return NULL, but there'd be no exception pending.

static String someMethod() { return null; }


I think you would benefit from reading the JNI book, which can be downloaded
from:
http://java.sun.com/docs/books/jni/
It's not too long, and is very helpful.

-- chris



 
Reply With Quote
 
Arash Nikkar
Guest
Posts: n/a
 
      02-20-2007
(NOTE: This might become a repost, as I tried to post this earlier)

Thanks to everyone for their help. I learned a couple of lessons here,
no more global jenv/job variables, error checking & clean up after
myself (i.e. release strings/arrays).

I never could get the GetEnv() method to work, so instead I just pass
the jenv/job variables between methods, that way the correct thread is
using the correct variables.

I have one last question: Do I need to ReleaseFloatArray if I created
it using NewFloatArray?

i.e.:

jfloat realGraph[5000];

for (i=0;i<5000;i++) {
realGraph[i] = SampleData[i];
}

jfloatArray returnArray = jenv->NewFloatArray(5000);

jenv->SetFloatArrayRegion(returnArray,
0,5000,realGraph);

jenv->CallVoidMethod(job, addPoints, returnArray);

do I need to release returnArray? or realGraph for that matter?

thanks again to all who provided input!!

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
float to string to float, with first float == second float Carsten Fuchs C++ 45 10-08-2009 09:47 AM
operator== (float, float) Jukka Lehtonen C++ 5 08-05-2004 08:28 AM
need code to convert float format to internal java float format which is kept in 4 bytes integer Andy Java 7 05-10-2004 09:26 PM
static_cast<float>(a) versus float(a) Jim West C++ 4 01-16-2004 12:36 PM
Re: float->byte->float is same with original float image. why float->ubyte->float is different??? bd C Programming 0 07-07-2003 12:09 AM



Advertisments