X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=bindings%2Fjava%2Forg%2Fsigrok%2Fcore%2Fclasses%2Fclasses.i;h=dda333df09dc7762a6057779f93abede14995e91;hb=e13648d0416aa0cb3c81f234389c92a30d46d527;hp=daa66305a37e527d0eca6ee3051b6350d9e0ec58;hpb=f2831ab35b4988930535dfd135884873b1b5b00d;p=libsigrok.git diff --git a/bindings/java/org/sigrok/core/classes/classes.i b/bindings/java/org/sigrok/core/classes/classes.i index daa66305..dda333df 100644 --- a/bindings/java/org/sigrok/core/classes/classes.i +++ b/bindings/java/org/sigrok/core/classes/classes.i @@ -72,7 +72,7 @@ namespace Glib { jclass Value = jenv->FindClass("org/sigrok/core/classes/" #JValue); jmethodID Value_init = jenv->GetMethodID(Value, "", "(JZ)V"); $result = jenv->NewObject(Vector, Vector_init); - jlong value; + jlong value = 0; for (auto entry : $1) { *(CValue **) &value = new CValue(entry); @@ -146,7 +146,7 @@ MAP_COMMON(std::string, std::shared_ptr, String, ClassName) jclass Value = jenv->FindClass("org/sigrok/core/classes/" #ClassName); jmethodID Value_init = jenv->GetMethodID(Value, "", "(JZ)V"); $result = jenv->NewObject(HashMap, HashMap_init); - jlong value; + jlong value = 0; for (auto entry : $1) { *(std::shared_ptr< sigrok::ClassName > **)&value = @@ -181,8 +181,8 @@ MAP_COMMON(const sigrok::ConfigKey *, Glib::VariantBase, ConfigKey, Variant) jclass Variant = jenv->FindClass("org/sigrok/core/classes/Variant"); jmethodID Variant_init = jenv->GetMethodID(Variant, "", "(JZ)V"); $result = jenv->NewObject(HashMap, HashMap_init); - jlong key; - jlong value; + jlong key = 0; + jlong value = 0; for (auto entry : $1) { *(const sigrok::ConfigKey **) &key = entry.first; @@ -198,11 +198,11 @@ MAP_COMMON(const sigrok::ConfigKey *, Glib::VariantBase, ConfigKey, Variant) MAP_COMMON(const sigrok::ConfigKey *, std::set, ConfigKey, java.util.Set) -%typemap(jni) std::map> "jobject" -%typemap(jtype) std::map> +%typemap(jni) std::map > "jobject" +%typemap(jtype) std::map > "java.util.Map>" -%typemap(out) std::map> { +%typemap(out) std::map > { jclass HashMap = jenv->FindClass("java/util/HashMap"); jmethodID HashMap_init = jenv->GetMethodID(HashMap, "", "()V"); jmethodID HashMap_put = jenv->GetMethodID(HashMap, "put", @@ -217,7 +217,7 @@ MAP_COMMON(const sigrok::ConfigKey *, std::set, jmethodID Capability_swigToEnum = jenv->GetStaticMethodID(Capability, "swigToEnum", "(I)Lorg/sigrok/core/classes/Capability;"); $result = jenv->NewObject(HashMap, HashMap_init); - jlong key; + jlong key = 0; for (auto map_entry : $1) { *(const sigrok::ConfigKey **) &key = map_entry.first; @@ -237,6 +237,74 @@ MAP_COMMON(const sigrok::ConfigKey *, std::set, $1 = jenv; %} +/* Thread safe JNIEnv handling */ + +%inline { +namespace { + class ScopedEnv { + public: + ScopedEnv(JavaVM *jvm); + ScopedEnv(const ScopedEnv &ref) = delete; + ~ScopedEnv(); + JNIEnv* operator-> () { return env; } + operator bool () const { return (bool)env; } + private: + JavaVM *jvm; + JNIEnv *env; + int env_status; + }; + ScopedEnv::ScopedEnv(JavaVM *jvm) : jvm(jvm), env(NULL) { + env_status = jvm->GetEnv((void **)&env, JNI_VERSION_1_2); + if (env_status == JNI_EDETACHED) { +%#if defined(__ANDROID__) + jvm->AttachCurrentThread(&env, NULL); +%#else + jvm->AttachCurrentThread((void **)&env, NULL); +%#endif + } + } + ScopedEnv::~ScopedEnv() { + if (env_status == JNI_EDETACHED) { + jvm->DetachCurrentThread(); + } + } +} +} + +/* "Smartpointer" for Java references. */ + +%inline { +namespace { + class GlobalRefBase + { + protected: + GlobalRefBase (JavaVM *jvm, jobject ref); + GlobalRefBase (const GlobalRefBase &ref) = delete; + ~GlobalRefBase (); + JavaVM *jvm; + jobject jref; + }; + GlobalRefBase::GlobalRefBase (JavaVM *jvm, jobject ref) : jvm(jvm), jref(0) { + ScopedEnv env(jvm); + if (env && ref) + jref = env->NewGlobalRef(ref); + } + GlobalRefBase::~GlobalRefBase () { + ScopedEnv env(jvm); + if(env && jref) + env->DeleteGlobalRef(jref); + } + template + class GlobalRef : private GlobalRefBase + { + public: + GlobalRef (JavaVM *jvm, Jtype ref) : GlobalRefBase(jvm, ref) {} + GlobalRef (const GlobalRef &ref) : GlobalRefBase(ref.jvm, ref.jref) {} + operator Jtype () const { return static_cast(jref); } + }; +} +} + /* Support Java log callbacks. */ %typemap(javaimports) sigrok::Context @@ -255,19 +323,23 @@ typedef jobject jlogcallback; { void add_log_callback(JNIEnv *env, jlogcallback obj) { + JavaVM *jvm = NULL; + env->GetJavaVM(&jvm); jclass obj_class = env->GetObjectClass(obj); jmethodID method = env->GetMethodID(obj_class, "run", "(Lorg/sigrok/core/classes/LogLevel;Ljava/lang/String;)V"); - jclass LogLevel = (jclass) env->NewGlobalRef( - env->FindClass("org/sigrok/core/classes/LogLevel")); + GlobalRef LogLevel(jvm, env->FindClass("org/sigrok/core/classes/LogLevel")); jmethodID LogLevel_init = env->GetMethodID(LogLevel, "", "(JZ)V"); - jobject obj_ref = env->NewGlobalRef(obj); + GlobalRef obj_ref(jvm, obj); $self->set_log_callback([=] ( const sigrok::LogLevel *loglevel, std::string message) { - jlong loglevel_addr; + ScopedEnv env(jvm); + if (!env) + throw sigrok::Error(SR_ERR); + jlong loglevel_addr = 0; *(const sigrok::LogLevel **) &loglevel_addr = loglevel; jobject loglevel_obj = env->NewObject( LogLevel, LogLevel_init, loglevel_addr, false); @@ -297,23 +369,26 @@ typedef jobject jdatafeedcallback; { void add_datafeed_callback(JNIEnv *env, jdatafeedcallback obj) { + JavaVM *jvm = NULL; + env->GetJavaVM(&jvm); jclass obj_class = env->GetObjectClass(obj); jmethodID method = env->GetMethodID(obj_class, "run", "(Lorg/sigrok/core/classes/Device;Lorg/sigrok/core/classes/Packet;)V"); - jclass Device = (jclass) env->NewGlobalRef( - env->FindClass("org/sigrok/core/classes/Device")); + GlobalRef Device(jvm, env->FindClass("org/sigrok/core/classes/Device")); jmethodID Device_init = env->GetMethodID(Device, "", "(JZ)V"); - jclass Packet = (jclass) env->NewGlobalRef( - env->FindClass("org/sigrok/core/classes/Packet")); + GlobalRef Packet(jvm, env->FindClass("org/sigrok/core/classes/Packet")); jmethodID Packet_init = env->GetMethodID(Packet, "", "(JZ)V"); - jobject obj_ref = env->NewGlobalRef(obj); + GlobalRef obj_ref(jvm, obj); $self->add_datafeed_callback([=] ( std::shared_ptr device, std::shared_ptr packet) { - jlong device_addr; - jlong packet_addr; + ScopedEnv env(jvm); + if (!env) + throw sigrok::Error(SR_ERR); + jlong device_addr = 0; + jlong packet_addr = 0; *(std::shared_ptr **) &device_addr = new std::shared_ptr(device); *(std::shared_ptr **) &packet_addr =