diff options
author | Sven Gothel <[email protected]> | 2020-06-29 05:59:08 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-06-29 05:59:08 +0200 |
commit | 0b7e94850a0bb5e4d389709bc9c449cd4f7dc094 (patch) | |
tree | 852b5353ac669275145bbb5097692b8ce579df9a | |
parent | 809487569a0e521bd9a5850cfbee00c2ee524932 (diff) |
Resolve regression calling DBTNativeDownlink.delete() having notifyDeleted() being called back from deleteNativeJavaObject(..)
Regression introduced with commit 83e0c7f75b4206701c1b9c62ebd4282f50f92a31
DBTNativeDownlink.delete() calls DBTNativeDownlink.deleteNativeJavaObject(..),
which by itself now calls back using DBTNativeDownlink.notifyDeleted() and purges isValid and nativeInstance.
Therefor, DBTNativeDownlink.delete() needs to cache the nativeInstance reference and pass it
down to DBTNativeDownlink.deleteImpl(long) as argument.
Further refine synchronization, using a local Object and isValid being an AtomicBoolean
to allow isValid() return the current state.
-rw-r--r-- | java/direct_bt/tinyb/DBTAdapter.java | 2 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTDevice.java | 2 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTGattCharacteristic.java | 2 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTGattDescriptor.java | 2 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTGattService.java | 2 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTManager.java | 5 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTNativeDownlink.java | 68 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTAdapter.cxx | 5 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 5 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattCharacteristic.cxx | 5 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattDescriptor.cxx | 5 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattService.cxx | 5 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTManager.cxx | 5 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTNativeDownlink.cxx | 6 |
14 files changed, 72 insertions, 47 deletions
diff --git a/java/direct_bt/tinyb/DBTAdapter.java b/java/direct_bt/tinyb/DBTAdapter.java index 17b975f9..b10eb02c 100644 --- a/java/direct_bt/tinyb/DBTAdapter.java +++ b/java/direct_bt/tinyb/DBTAdapter.java @@ -303,7 +303,7 @@ public class DBTAdapter extends DBTObject implements BluetoothAdapter /* internal */ @Override - protected native void deleteImpl(); + protected native void deleteImpl(long nativeInstance); /* discovery */ diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java index 6a0ca25c..8f0b0c4e 100644 --- a/java/direct_bt/tinyb/DBTDevice.java +++ b/java/direct_bt/tinyb/DBTDevice.java @@ -597,7 +597,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice * </p> */ @Override - protected native void deleteImpl(); + protected native void deleteImpl(long nativeInstance); @Override public native boolean addCharacteristicListener(final GATTCharacteristicListener listener, final BluetoothGattCharacteristic characteristicMatch); diff --git a/java/direct_bt/tinyb/DBTGattCharacteristic.java b/java/direct_bt/tinyb/DBTGattCharacteristic.java index ccca1ae4..bd7f0dea 100644 --- a/java/direct_bt/tinyb/DBTGattCharacteristic.java +++ b/java/direct_bt/tinyb/DBTGattCharacteristic.java @@ -322,6 +322,6 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha private native boolean enableValueNotificationsImpl(boolean v); @Override - protected native void deleteImpl(); + protected native void deleteImpl(long nativeInstance); } diff --git a/java/direct_bt/tinyb/DBTGattDescriptor.java b/java/direct_bt/tinyb/DBTGattDescriptor.java index 86b27530..2733f8ba 100644 --- a/java/direct_bt/tinyb/DBTGattDescriptor.java +++ b/java/direct_bt/tinyb/DBTGattDescriptor.java @@ -167,5 +167,5 @@ public class DBTGattDescriptor extends DBTObject implements BluetoothGattDescrip private native boolean writeValueImpl(byte[] argValue) throws BluetoothException; @Override - protected native void deleteImpl(); + protected native void deleteImpl(long nativeInstance); } diff --git a/java/direct_bt/tinyb/DBTGattService.java b/java/direct_bt/tinyb/DBTGattService.java index 3bdb45a8..98081e25 100644 --- a/java/direct_bt/tinyb/DBTGattService.java +++ b/java/direct_bt/tinyb/DBTGattService.java @@ -131,5 +131,5 @@ public class DBTGattService extends DBTObject implements BluetoothGattService private native List<BluetoothGattCharacteristic> getCharacteristicsImpl(); @Override - protected native void deleteImpl(); + protected native void deleteImpl(long nativeInstance); } diff --git a/java/direct_bt/tinyb/DBTManager.java b/java/direct_bt/tinyb/DBTManager.java index c74f0706..263b7365 100644 --- a/java/direct_bt/tinyb/DBTManager.java +++ b/java/direct_bt/tinyb/DBTManager.java @@ -43,6 +43,7 @@ import org.tinyb.BluetoothType; public class DBTManager implements BluetoothManager { protected static final boolean DEBUG = BluetoothFactory.DEBUG; + protected static final boolean VERBOSE = BluetoothFactory.VERBOSE; private static volatile boolean isJVMShuttingDown = false; private static final List<Runnable> userShutdownHooks = new ArrayList<Runnable>(); @@ -269,7 +270,7 @@ public class DBTManager implements BluetoothManager private native List<BluetoothAdapter> getAdapterListImpl(); private native void initImpl(final boolean unifyUUID128Bit) throws BluetoothException; - private native void deleteImpl(); + private native void deleteImpl(long nativeInstance); private DBTManager() { initImpl(unifyUUID128Bit); @@ -304,7 +305,7 @@ public class DBTManager implements BluetoothManager a.close(); } adapters.clear(); - deleteImpl(); + deleteImpl(nativeInstance); } } diff --git a/java/direct_bt/tinyb/DBTNativeDownlink.java b/java/direct_bt/tinyb/DBTNativeDownlink.java index d3535ce0..c45bdb23 100644 --- a/java/direct_bt/tinyb/DBTNativeDownlink.java +++ b/java/direct_bt/tinyb/DBTNativeDownlink.java @@ -25,12 +25,15 @@ package direct_bt.tinyb; +import java.util.concurrent.atomic.AtomicBoolean; + import org.tinyb.BluetoothFactory; public abstract class DBTNativeDownlink { - protected long nativeInstance; - private boolean isValid; + private long nativeInstance; + private final AtomicBoolean isValid = new AtomicBoolean(false); + private final Object nativeLock = new Object(); static { BluetoothFactory.checkInitialized(); @@ -39,11 +42,11 @@ public abstract class DBTNativeDownlink protected DBTNativeDownlink(final long nativeInstance) { this.nativeInstance = nativeInstance; - isValid = true; + isValid.set(true); initNativeJavaObject(nativeInstance); } - protected final boolean isValid() { return isValid; } + protected final boolean isValid() { return isValid.get(); } @Override protected void finalize() @@ -52,41 +55,62 @@ public abstract class DBTNativeDownlink } /** - * Deletes the native instance in the following order + * Deletes the {@code nativeInstance} in the following order * <ol> - * <li>Removes this java reference from the native instance</li> - * <li>Deletes the native instance via {@link #deleteImpl()}</li> - * <li>Sets the nativeInstance := 0</li> + * <li>Removes this java reference from the {@code nativeInstance}</li> + * <li>Deletes the {@code nativeInstance} via {@link #deleteImpl(long)}</li> + * <li>Zeros the {@code nativeInstance} reference</li> * </ol> */ - public synchronized void delete() { - if (!isValid) { - return; + public final void delete() { + synchronized (nativeLock) { + if( !isValid.compareAndSet(true, false) ) { + if( DBTManager.DEBUG ) { + System.err.println("JAVA: delete: !valid -> bail: "+getClass().getSimpleName()); + } + return; + } + if( DBTManager.DEBUG ) { + System.err.println("JAVA: delete.0: "+getClass().getSimpleName()+": valid, handle 0x"+Long.toHexString(nativeInstance)); + } + final long _nativeInstance = nativeInstance; + nativeInstance = 0; + deleteNativeJavaObject(_nativeInstance); // will issue notifyDeleted() itself! + deleteImpl(_nativeInstance); + if( DBTManager.DEBUG ) { + System.err.println("JAVA: delete.X: "+getClass().getSimpleName()+": handle 0x"+Long.toHexString(nativeInstance)); + } } - isValid = false; - deleteNativeJavaObject(nativeInstance); - deleteImpl(); - nativeInstance = 0; } /** * Called from native JavaUplink dtor -> JavaGlobalObj dtor, * i.e. native instance destructed in native land. */ - private synchronized void notifyDeleted() { - isValid = false; - nativeInstance = 0; - // System.err.println("***** notifyDeleted: "+getClass().getSimpleName()+": valid "+isValid+" -> false, handle 0x"+Long.toHexString(nativeInstance)+" -> null: "+toString()); + private final void notifyDeleted() { + synchronized (nativeLock) { + final boolean _isValid = isValid.get(); + final long _nativeInstance = nativeInstance; + isValid.set(false); + nativeInstance = 0; + if( DBTManager.DEBUG ) { + System.err.println("JAVA: delete.notifyDeleted: "+getClass().getSimpleName()+", was: valid "+_isValid+", handle 0x"+Long.toHexString(_nativeInstance)+": "+toString()); + } + } } /** * Deletes the native instance. * <p> - * Called via {@link #delete()} and at this point this java reference - * has been removed from the native instance. + * Called via {@link #delete()} and at this point + * <ul> + * <li>this java reference has been removed from the native instance, i.e. {@code JavaUplink}'s {@code javaObjectRef = nullptr}</li> + * <li>the {@link #nativeInstance} reference has been zeroed, but passed as argument for this final native deletion task.</li> + * </ul> * </p> + * @param nativeInstance copy of {@link #nativeInstance} reference, which has been already zeroed. */ - protected abstract void deleteImpl(); + protected abstract void deleteImpl(long nativeInstance); private native void initNativeJavaObject(final long nativeInstance); private native void deleteNativeJavaObject(final long nativeInstance); diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx index 3a8892d6..5adbefbd 100644 --- a/java/jni/direct_bt/DBTAdapter.cxx +++ b/java/jni/direct_bt/DBTAdapter.cxx @@ -507,10 +507,11 @@ jstring Java_direct_1bt_tinyb_DBTAdapter_toStringImpl(JNIEnv *env, jobject obj) return nullptr; } -void Java_direct_1bt_tinyb_DBTAdapter_deleteImpl(JNIEnv *env, jobject obj) +void Java_direct_1bt_tinyb_DBTAdapter_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance) { + (void)obj; try { - DBTAdapter *adapter = getInstance<DBTAdapter>(env, obj); + DBTAdapter *adapter = castInstance<DBTAdapter>(nativeInstance); DBG_PRINT("Java_direct_1bt_tinyb_DBTAdapter_deleteImpl %s", adapter->toString().c_str()); delete adapter; } catch(...) { diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx index 55e074cf..e0acb004 100644 --- a/java/jni/direct_bt/DBTDevice.cxx +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -246,10 +246,11 @@ jint Java_direct_1bt_tinyb_DBTDevice_removeAllCharacteristicListener(JNIEnv *env return 0; } -void Java_direct_1bt_tinyb_DBTDevice_deleteImpl(JNIEnv *env, jobject obj) +void Java_direct_1bt_tinyb_DBTDevice_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance) { + (void)obj; try { - DBTDevice *device = getInstance<DBTDevice>(env, obj); + DBTDevice *device = castInstance<DBTDevice>(nativeInstance); device->remove(); // No delete: DBTDevice instance owned by DBTAdapter // However, device->remove() might issue destruction diff --git a/java/jni/direct_bt/DBTGattCharacteristic.cxx b/java/jni/direct_bt/DBTGattCharacteristic.cxx index fb966a93..d7541e2e 100644 --- a/java/jni/direct_bt/DBTGattCharacteristic.cxx +++ b/java/jni/direct_bt/DBTGattCharacteristic.cxx @@ -48,9 +48,10 @@ jstring Java_direct_1bt_tinyb_DBTGattCharacteristic_toStringImpl(JNIEnv *env, jo return nullptr; } -void Java_direct_1bt_tinyb_DBTGattCharacteristic_deleteImpl(JNIEnv *env, jobject obj) { +void Java_direct_1bt_tinyb_DBTGattCharacteristic_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance) { + (void)obj; try { - GATTCharacteristic *characteristic = getInstance<GATTCharacteristic>(env, obj); + GATTCharacteristic *characteristic = castInstance<GATTCharacteristic>(nativeInstance); (void)characteristic; // No delete: Service instance owned by GATTService -> DBTDevice } catch(...) { diff --git a/java/jni/direct_bt/DBTGattDescriptor.cxx b/java/jni/direct_bt/DBTGattDescriptor.cxx index 17a1a118..081fda33 100644 --- a/java/jni/direct_bt/DBTGattDescriptor.cxx +++ b/java/jni/direct_bt/DBTGattDescriptor.cxx @@ -47,9 +47,10 @@ void Java_direct_1bt_tinyb_DBTGattDescriptor_deleteImpl(JNIEnv *env, jobject obj } } -jstring Java_direct_1bt_tinyb_DBTGattDescriptor_toStringImpl(JNIEnv *env, jobject obj) { +jstring Java_direct_1bt_tinyb_DBTGattDescriptor_toStringImpl(JNIEnv *env, jobject obj, jlong nativeInstance) { + (void)obj; try { - GATTDescriptor *nativePtr = getInstance<GATTDescriptor>(env, obj); + GATTDescriptor *nativePtr = castInstance<GATTDescriptor>(nativeInstance); JavaGlobalObj::check(nativePtr->getJavaObject(), E_FILE_LINE); return from_string_to_jstring(env, nativePtr->toString()); } catch(...) { diff --git a/java/jni/direct_bt/DBTGattService.cxx b/java/jni/direct_bt/DBTGattService.cxx index f00f9e2f..fcb234e8 100644 --- a/java/jni/direct_bt/DBTGattService.cxx +++ b/java/jni/direct_bt/DBTGattService.cxx @@ -49,9 +49,10 @@ jstring Java_direct_1bt_tinyb_DBTGattService_toStringImpl(JNIEnv *env, jobject o } -void Java_direct_1bt_tinyb_DBTGattService_deleteImpl(JNIEnv *env, jobject obj) { +void Java_direct_1bt_tinyb_DBTGattService_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance) { + (void)obj; try { - GATTService *service = getInstance<GATTService>(env, obj); + GATTService *service = castInstance<GATTService>(nativeInstance); (void)service; // No delete: Service instance owned by DBTDevice } catch(...) { diff --git a/java/jni/direct_bt/DBTManager.cxx b/java/jni/direct_bt/DBTManager.cxx index 560a0f92..3a02540f 100644 --- a/java/jni/direct_bt/DBTManager.cxx +++ b/java/jni/direct_bt/DBTManager.cxx @@ -53,10 +53,11 @@ void Java_direct_1bt_tinyb_DBTManager_initImpl(JNIEnv *env, jobject obj, jboolea } } -void Java_direct_1bt_tinyb_DBTManager_deleteImpl(JNIEnv *env, jobject obj) +void Java_direct_1bt_tinyb_DBTManager_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance) { + (void)obj; try { - DBTManager *manager = getInstance<DBTManager>(env, obj); // special: static singleton + DBTManager *manager = castInstance<DBTManager>(nativeInstance); // special: static singleton manager->close(); manager->setJavaObject(nullptr); (void) manager; diff --git a/java/jni/direct_bt/DBTNativeDownlink.cxx b/java/jni/direct_bt/DBTNativeDownlink.cxx index 77afbd7f..934bf0ca 100644 --- a/java/jni/direct_bt/DBTNativeDownlink.cxx +++ b/java/jni/direct_bt/DBTNativeDownlink.cxx @@ -40,9 +40,6 @@ void Java_direct_1bt_tinyb_DBTNativeDownlink_initNativeJavaObject(JNIEnv *env, j { try { JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance); - if( nullptr == javaUplink ) { - throw InternalError("NativeInstance JavaUplink is NULL", E_FILE_LINE); - } jclass javaClazz = search_class(env, obj); java_exception_check_and_throw(env, E_FILE_LINE); if( nullptr == javaClazz ) { @@ -67,9 +64,6 @@ void Java_direct_1bt_tinyb_DBTNativeDownlink_deleteNativeJavaObject(JNIEnv *env, (void)obj; try { JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance); - if( nullptr == javaUplink ) { - throw InternalError("NativeInstance JavaUplink is NULL", E_FILE_LINE); - } DBG_PRINT("Java_direct_1bt_tinyb_DBTNativeDownlink_deleteNativeJavaObject %p -> %s", javaUplink, javaUplink->toString().c_str()); javaUplink->setJavaObject(nullptr); } catch(...) { |