static void callback_dispatch(ffi_cif* cif, void* resp, void** cbargs, void* user_data) { callback* cb = ((callback *)user_data); JavaVM* jvm = cb->vm; JNIEnv* env; int was_attached = (*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_4) == JNI_OK; jboolean detach = was_attached ? JNI_FALSE : JNI_TRUE; if (!was_attached) { int attach_status = 0; JavaVMAttachArgs args; jobject group = NULL; int daemon = JNI_FALSE; args.version = JNI_VERSION_1_2; args.name = NULL; args.group = NULL; if (cb->behavior_flags & CB_HAS_INITIALIZER) { AttachOptions options; options.daemon = JNI_FALSE; // default non-daemon options.detach = JNI_TRUE; // default detach behavior options.name = NULL; args.group = initializeThread(cb, &options); daemon = options.daemon ? JNI_TRUE : JNI_FALSE; detach = options.detach ? JNI_TRUE : JNI_FALSE; args.name = options.name; } if (daemon) { attach_status = (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void*)&env, &args); } else { attach_status = (*jvm)->AttachCurrentThread(jvm, (void *)&env, &args); } if (attach_status != JNI_OK) { fprintf(stderr, "JNA: Can't attach native thread to VM for callback: %d\n", attach_status); return; } if (args.group) { (*env)->DeleteWeakGlobalRef(env, args.group); } } // Give the callback glue its own local frame to ensure all local references // are properly disposed if ((*env)->PushLocalFrame(env, 16) < 0) { fprintf(stderr, "JNA: Out of memory: Can't allocate local frame"); } else { // Kind of a hack, use last error value rather than setting up our own TLS setLastError(0); callback_invoke(env, cb, cif, resp, cbargs); // Must be invoked immediately after return to avoid anything // stepping on errno/GetLastError switch(lastError()) { case THREAD_LEAVE_ATTACHED: detach = JNI_FALSE; break; case THREAD_DETACH: detach = JNI_TRUE; break; default: break; /* use default detach behavior */ } (*env)->PopLocalFrame(env, NULL); } if (detach) { (*jvm)->DetachCurrentThread(jvm); } }
static void callback_dispatch(ffi_cif* cif, void* resp, void** cbargs, void* user_data) { callback* cb = ((callback *)user_data); JavaVM* jvm = cb->vm; JNIEnv* env = NULL; int was_attached = (*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_4) == JNI_OK; jboolean detach = was_attached ? JNI_FALSE : JNI_TRUE; thread_storage* tls = was_attached ? get_thread_storage(env) : NULL; if (!was_attached) { int attach_status = 0; JavaVMAttachArgs args; int daemon = JNI_FALSE; args.version = JNI_VERSION_1_2; args.name = NULL; args.group = NULL; if (cb->behavior_flags & CB_HAS_INITIALIZER) { AttachOptions options; options.daemon = JNI_FALSE; // default non-daemon options.detach = JNI_TRUE; // default detach behavior options.name = NULL; args.group = initializeThread(cb, &options); daemon = options.daemon ? JNI_TRUE : JNI_FALSE; detach = options.detach ? JNI_TRUE : JNI_FALSE; args.name = options.name; } if (daemon) { attach_status = (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void*)&env, &args); } else { attach_status = (*jvm)->AttachCurrentThread(jvm, (void *)&env, &args); } tls = get_thread_storage(env); if (tls) { snprintf(tls->name, sizeof(tls->name), "%s", args.name ? args.name : "<unconfigured native thread>"); tls->detach = detach; tls->jvm_thread = JNI_FALSE; } // Dispose of allocated memory free(args.name); if (attach_status != JNI_OK) { fprintf(stderr, "JNA: Can't attach native thread to VM for callback: %d\n", attach_status); return; } if (args.group) { (*env)->DeleteWeakGlobalRef(env, args.group); } } if (!tls) { fprintf(stderr, "JNA: couldn't obtain thread-local storage\n"); return; } // Give the callback glue its own local frame to ensure all local references // are properly disposed if ((*env)->PushLocalFrame(env, 16) < 0) { fprintf(stderr, "JNA: Out of memory: Can't allocate local frame\n"); } else { callback_invoke(env, cb, cif, resp, cbargs); // Make note of whether the callback wants to avoid detach detach = tls->detach && !tls->jvm_thread; (*env)->PopLocalFrame(env, NULL); } if (detach) { if ((*jvm)->DetachCurrentThread(jvm) != 0) { fprintf(stderr, "JNA: could not detach thread\n"); } } }