On Apr 16, 2:42 am, extrapedestrian <
extra.pedestr...@gmail.com>
wrote:
[...]
I commented on a few things I noticed in the code.
> // get a local java env
> envErr = (*g_vm)->AttachCurrentThread( g_vm, (void**)&t_env, NULL );
> if ( envErr != 0 ){
> if ( (*t_env)->ExceptionCheck( t_env ) == JNI_TRUE ){
> (*t_env)->ExceptionDescribe( t_env );
> }
> fprintf(logfile,"Receive thread: error exception\n");
> (*g_vm)->DetachCurrentThread(g_vm);
> return NULL;
> }
> if((*t_env)->ExceptionOccurred(t_env)){
> (*t_env)->ExceptionDescribe(t_env);
> }
> if (t_env == NULL) {
> fprintf(logfile,"Receive thread: failed to get ENV pointer in
> pushContext\n");
> (*g_vm)->DetachCurrentThread(g_vm);
> return NULL;
> }
It's good to check for exceptions after making JNI calls. In this
case, however, you should *not* check for exceptions if
AttachCurrentThread fails. If it fails, t_env will not be valid, and
calls that use it will likely crash.
If the call succeeds, no exceptions will be pending in this thread,
and you can omit the second check too. Also, if the call succeeds,
you don't need to compare t_env to NULL.
> //thread could run indefinitely in while loop
> //while(1)
> //{
> fprintf(logfile,"Receive thread: Start receive on socket: %d\n", s);
> if ((t=recv(s, str_l, 100, 0)) > 0)
> {
> str_l[t] = '\0';
> fprintf(logfile,"Receive thread: Server response: \"%s\"\n",
> str_l);
> (*t_env)->CallVoidMethod(t_env,g_obj,g_mid,(*t_env)->NewStringUTF
> (t_env, str_l));
> }
> else
> {
> if (t < 0) perror("recv");
> else printf("Receive thread: Server closed connection\n");
> (*g_vm)->DetachCurrentThread(g_vm);
> return NULL;
> }
> //}
>
> fclose(logfile);
>
> (*g_vm)->DetachCurrentThread(g_vm);
>
> return NULL;
>
> }
Two thoughts here:
(1) If you do choose to loop forever, be aware that NewStringUTF
creates a local reference. If you don't return to Java and don't
delete it, they will build up and eventually overflow the table.
(2) Every Attach / Detach creates a Thread object and does some
internal housekeeping. If you're doing this frequently the overhead
may become problematic.
> JNIEXPORT jstring JNICALL
> Java_com_rtrk_jnicbus_NativeMessenger_sendMessage(JNIEnv *env, jclass
> cls, jstring question)
> {
[...]
> //get string parameter passed from java function
> str = (char*) (*env)->GetStringUTFChars(env, question, NULL);
[...]
> //open unix socket
> if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
> fprintf(logfile,"error: socket\n");
> return NULL;
> }
There are a couple of places where you "return NULL" without calling
ReleaseStringUTFChars. You will leak memory whenever there is an
error.
> //startCallback is called to store callback function ID
> //java class object is stored in global variable and used
> //in receiving thread to call callback function
[...]
> g_obj = (*env)->NewGlobalRef(env, obj);
If this can be called more than once, you should DeleteGlobalRef
(g_obj) before reassigning it. If it can't, an "assert(g_obj ==
NULL)" would help ensure that. Otherwise, you will leak global
references.