$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();
+ }
+ }
+}
+}
+
/* Support Java log callbacks. */
%typemap(javaimports) sigrok::Context
{
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");
const sigrok::LogLevel *loglevel,
std::string message)
{
+ 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(
{
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");
std::shared_ptr<sigrok::Device> device,
std::shared_ptr<sigrok::Packet> packet)
{
+ ScopedEnv env(jvm);
+ if (!env)
+ throw sigrok::Error(SR_ERR);
jlong device_addr = 0;
jlong packet_addr = 0;
*(std::shared_ptr<sigrok::Device> **) &device_addr =