From 99eafd9c609add7f548fe1f15540634972c9c96c Mon Sep 17 00:00:00 2001 From: Eric House Date: Sat, 9 Mar 2019 07:17:07 -0800 Subject: [PATCH] add retain()/release() Seems to work but needs testing! --- .../eehouse/android/xw4/BoardDelegate.java | 1 + .../org/eehouse/android/xw4/GameLock.java | 19 ++++++++++++++++--- .../eehouse/android/xw4/jni/JNIThread.java | 12 ++---------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java index e3bcdb9ae..231b4a747 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java @@ -595,6 +595,7 @@ public class BoardDelegate extends DelegateBase } else { s_noLockCount = 0; m_jniThreadRef = JNIThread.getRetained( lock ); + lock.release(); // see http://stackoverflow.com/questions/680180/where-to-stop- \ // destroy-threads-in-android-service-class diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameLock.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameLock.java index a739f878a..606e80325 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameLock.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameLock.java @@ -28,6 +28,7 @@ import java.util.Formatter; import java.util.HashMap; import java.util.Map; import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; import android.support.annotation.NonNull; @@ -58,6 +59,7 @@ public class GameLock implements AutoCloseable, Serializable { // private static final long ASSERT_TIME = 2000; private static final long THROW_TIME = 1000; private long m_rowid; + private AtomicInteger m_lockCount = new AtomicInteger(1); private static class Owner { Thread mThread; @@ -314,15 +316,26 @@ public class GameLock implements AutoCloseable, Serializable { return getFor( rowid ).lockRO( maxMillis ); } - public void unlock() + public void release() { - getFor( m_rowid ).unlock(); + int count = m_lockCount.decrementAndGet(); + Log.d( TAG, "%s.release(): count NOW %d", this, count ); + if ( count == 0 ) { + getFor( m_rowid ).unlock(); + } + } + + public GameLock retain() + { + int count = m_lockCount.incrementAndGet(); + Log.d( TAG, "%s.retain(): count NOW %d", this, count ); + return this; } @Override public void close() { - unlock(); + release(); } public long getRowid() diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java index 102fd6898..b709f4a3a 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java @@ -165,7 +165,7 @@ public class JNIThread extends Thread implements AutoCloseable { private JNIThread( GameLock lock ) { - m_lock = lock; + m_lock = lock.retain(); m_rowid = lock.getRowid(); m_queue = new LinkedBlockingQueue(); } @@ -273,7 +273,7 @@ public class JNIThread extends Thread implements AutoCloseable { private synchronized void unlockOnce() { if ( null != m_lock ) { - m_lock.unlock(); + m_lock.release(); m_lock = null; } } @@ -866,14 +866,6 @@ public class JNIThread extends Thread implements AutoCloseable { if ( null == result && null != lock ) { result = new JNIThread( lock ); s_instances.put( rowid, result ); - } else if ( null != lock ) { - // unlock if we're not using it. This is a hack needed because - // we don't have retain/release semantics. The caller is done - // with the lock and expects us to keep it. If we don't need - // it we need to unlock it. Fix is for JNIThread.__init() to - // be able to retain() it and caller to release() it after we - // return. - lock.unlock(); } if ( null != result ) { result.retain_sync();