mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-13 20:48:02 +01:00
Make Board wait a bit for lock on opening
Was seeing frequent failure to open games as JNIThread.getRetained() was unable to get a lock without waiting. Which it can't do on UI thread. So added a method to GameLock that takes a callback to be called when the lock's obtained, with the actual waiting done on a local thread. Then fixed BoardDelegate a bit to not crash while waiting for the callback.
This commit is contained in:
parent
a8872df5ed
commit
d94217cc06
7 changed files with 101 additions and 37 deletions
|
@ -566,36 +566,49 @@ public class BoardDelegate extends DelegateBase
|
||||||
m_haveInvited = args.getBoolean( GameUtils.INVITED, false );
|
m_haveInvited = args.getBoolean( GameUtils.INVITED, false );
|
||||||
m_overNotShown = true;
|
m_overNotShown = true;
|
||||||
|
|
||||||
// getRetained() can in threory fail to get the lock and so will
|
GameLock.callWithLock( m_rowid, 100L, new Handler(),
|
||||||
// return null. Let m_jniThreadRef stay null in that case; doResume()
|
new GameLock.LockProc() {
|
||||||
// will finish() in that case.
|
@Override
|
||||||
m_jniThreadRef = JNIThread.getRetained( m_activity, m_rowid, true );
|
public void gotLock( GameLock lock ) {
|
||||||
if ( null != m_jniThreadRef ) {
|
if ( null == lock ) {
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
m_jniThreadRef = JNIThread.getRetained( lock );
|
||||||
|
|
||||||
// see http://stackoverflow.com/questions/680180/where-to-stop- \
|
// see http://stackoverflow.com/questions/680180/where-to-stop- \
|
||||||
// destroy-threads-in-android-service-class
|
// destroy-threads-in-android-service-class
|
||||||
m_jniThreadRef.setDaemonOnce( true );
|
m_jniThreadRef.setDaemonOnce( true );
|
||||||
m_jniThreadRef.startOnce();
|
m_jniThreadRef.startOnce();
|
||||||
|
|
||||||
NFCUtils.register( m_activity, this ); // Don't seem to need to unregister...
|
// Don't seem to need to unregister...
|
||||||
|
NFCUtils.register( m_activity, BoardDelegate.this );
|
||||||
|
|
||||||
setBackgroundColor();
|
setBackgroundColor();
|
||||||
setKeepScreenOn();
|
setKeepScreenOn();
|
||||||
|
|
||||||
|
doResume( true );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
} // init
|
} // init
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart()
|
protected void onStart()
|
||||||
{
|
{
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
if ( null != m_jniThreadRef ) {
|
||||||
doResume( true );
|
doResume( true );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
if ( null != m_jniThreadRef ) {
|
||||||
doResume( false );
|
doResume( false );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void onPause()
|
protected void onPause()
|
||||||
{
|
{
|
||||||
|
@ -2747,7 +2760,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
GamePtr gamePtr = null;
|
GamePtr gamePtr = null;
|
||||||
GameSummary summary = null;
|
GameSummary summary = null;
|
||||||
CurGameInfo gi = null;
|
CurGameInfo gi = null;
|
||||||
JNIThread thread = JNIThread.getRetained( activity, rowID );
|
JNIThread thread = JNIThread.getRetained( rowID );
|
||||||
if ( null != thread ) {
|
if ( null != thread ) {
|
||||||
gamePtr = thread.getGamePtr().retain();
|
gamePtr = thread.getGamePtr().retain();
|
||||||
summary = thread.getSummary();
|
summary = thread.getSummary();
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class ChatDelegate extends DelegateBase {
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
m_jniThreadRef = JNIThread.getRetained( m_activity, m_rowid );
|
m_jniThreadRef = JNIThread.getRetained( m_rowid );
|
||||||
if ( null == m_jniThreadRef ) {
|
if ( null == m_jniThreadRef ) {
|
||||||
Log.w( TAG, "onResume(): m_jniThreadRef null; exiting" );
|
Log.w( TAG, "onResume(): m_jniThreadRef null; exiting" );
|
||||||
finish();
|
finish();
|
||||||
|
|
|
@ -483,7 +483,7 @@ public class GameConfigDelegate extends DelegateBase
|
||||||
@Override
|
@Override
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
m_jniThread = JNIThread.getRetained( m_activity, m_rowid );
|
m_jniThread = JNIThread.getRetained( m_rowid );
|
||||||
super.onResume();
|
super.onResume();
|
||||||
loadGame();
|
loadGame();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
package org.eehouse.android.xw4;
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Formatter;
|
import java.util.Formatter;
|
||||||
|
@ -232,6 +234,58 @@ public class GameLock implements AutoCloseable {
|
||||||
return m_rowid;
|
return m_rowid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setOwner( Owner owner )
|
||||||
|
{
|
||||||
|
synchronized ( mOwners ) {
|
||||||
|
mOwners.pop();
|
||||||
|
mOwners.push( owner );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface LockProc {
|
||||||
|
public void gotLock( GameLock lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meant to be called from UI thread, returning immediately, but when it
|
||||||
|
// gets the lock, or time runs out, calls the callback (using the Handler
|
||||||
|
// passed in) with the lock or null.
|
||||||
|
public static void callWithLock( final long rowid,
|
||||||
|
final long maxMillis,
|
||||||
|
final Handler handler,
|
||||||
|
final LockProc proc )
|
||||||
|
{
|
||||||
|
// capture caller thread and stack
|
||||||
|
final Owner owner = new Owner();
|
||||||
|
|
||||||
|
new Thread( new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GameLock lock = null;
|
||||||
|
if ( false && 0 == Utils.nextRandomInt() % 5 ) {
|
||||||
|
Log.d( TAG, "testing return-null case" );
|
||||||
|
try {
|
||||||
|
Thread.sleep( maxMillis );
|
||||||
|
} catch ( Exception ex) {}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
lock = GameLock
|
||||||
|
.getFor( rowid )
|
||||||
|
.lockImpl( maxMillis, false );
|
||||||
|
lock.setOwner( owner );
|
||||||
|
} catch ( GameLockedException | InterruptedException gle ) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
final GameLock fLock = lock;
|
||||||
|
handler.post( new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
proc.gotLock( fLock );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} ).start();
|
||||||
|
}
|
||||||
|
|
||||||
// used only for asserts
|
// used only for asserts
|
||||||
public boolean canWrite()
|
public boolean canWrite()
|
||||||
{
|
{
|
||||||
|
|
|
@ -219,7 +219,7 @@ public class GameUtils {
|
||||||
long maxMillis )
|
long maxMillis )
|
||||||
{
|
{
|
||||||
GameSummary result = null;
|
GameSummary result = null;
|
||||||
JNIThread thread = JNIThread.getRetained( context, rowid );
|
JNIThread thread = JNIThread.getRetained( rowid );
|
||||||
GameLock lock = null;
|
GameLock lock = null;
|
||||||
if ( null != thread ) {
|
if ( null != thread ) {
|
||||||
lock = thread.getLock();
|
lock = thread.getLock();
|
||||||
|
@ -252,7 +252,7 @@ public class GameUtils {
|
||||||
long rowid = DBUtils.ROWID_NOTFOUND;
|
long rowid = DBUtils.ROWID_NOTFOUND;
|
||||||
GameLock lockSrc = null;
|
GameLock lockSrc = null;
|
||||||
|
|
||||||
JNIThread thread = JNIThread.getRetained( context, rowidIn );
|
JNIThread thread = JNIThread.getRetained( rowidIn );
|
||||||
if ( null != thread ) {
|
if ( null != thread ) {
|
||||||
lockSrc = thread.getLock();
|
lockSrc = thread.getLock();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1275,7 +1275,7 @@ public class GameUtils {
|
||||||
+ " failed for rowid %d", rowid );
|
+ " failed for rowid %d", rowid );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JNIThread jniThread = JNIThread.getRetained( m_context, rowid );
|
JNIThread jniThread = JNIThread.getRetained( rowid );
|
||||||
if ( null != jniThread ) {
|
if ( null != jniThread ) {
|
||||||
jniThread.handle( JNIThread.JNICmd.CMD_RESEND, false,
|
jniThread.handle( JNIThread.JNICmd.CMD_RESEND, false,
|
||||||
false, false );
|
false, false );
|
||||||
|
|
|
@ -76,7 +76,7 @@ abstract class XWServiceHelper {
|
||||||
{
|
{
|
||||||
boolean allConsumed = true;
|
boolean allConsumed = true;
|
||||||
boolean[] isLocalP = new boolean[1];
|
boolean[] isLocalP = new boolean[1];
|
||||||
JNIThread jniThread = JNIThread.getRetained( context, rowid );
|
JNIThread jniThread = JNIThread.getRetained( rowid );
|
||||||
boolean consumed = false;
|
boolean consumed = false;
|
||||||
if ( null != jniThread ) {
|
if ( null != jniThread ) {
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
@ -146,7 +146,7 @@ abstract class XWServiceHelper {
|
||||||
|
|
||||||
if ( null == gi ) {
|
if ( null == gi ) {
|
||||||
// locked. Maybe it's open?
|
// locked. Maybe it's open?
|
||||||
JNIThread thread = JNIThread.getRetained( mService, rowid );
|
JNIThread thread = JNIThread.getRetained( rowid );
|
||||||
if ( null != thread ) {
|
if ( null != thread ) {
|
||||||
gi = thread.getGI();
|
gi = thread.getGI();
|
||||||
thread.release( false );
|
thread.release( false );
|
||||||
|
|
|
@ -823,27 +823,24 @@ public class JNIThread extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JNIThread getRetained( Context context, long rowid )
|
public static JNIThread getRetained( long rowid )
|
||||||
{
|
{
|
||||||
return getRetained( context, rowid, false );
|
return getRetained( rowid, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JNIThread getRetained( Context context, long rowid, boolean makeNew )
|
public static JNIThread getRetained( GameLock lock )
|
||||||
|
{
|
||||||
|
return getRetained( lock.getRowid(), lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JNIThread getRetained( long rowid, GameLock lock )
|
||||||
{
|
{
|
||||||
JNIThread result = null;
|
JNIThread result = null;
|
||||||
synchronized( s_instances ) {
|
synchronized( s_instances ) {
|
||||||
result = s_instances.get( rowid );
|
result = s_instances.get( rowid );
|
||||||
if ( null == result && makeNew ) {
|
if ( null == result && null != lock ) {
|
||||||
DbgUtils.assertOnUIThread(); // can't use GameLock.lock()
|
|
||||||
if ( true /*test done*/ || (0 != Utils.nextRandomInt() % 3) ) {
|
|
||||||
GameLock lock = GameLock.getFor( rowid ).tryLock();
|
|
||||||
if ( lock != null ) {
|
|
||||||
result = new JNIThread( lock );
|
result = new JNIThread( lock );
|
||||||
s_instances.put( rowid, result );
|
s_instances.put( rowid, result );
|
||||||
} else {
|
|
||||||
DbgUtils.toastNoLock( TAG, context, "getRetained(%d)", rowid );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ( null != result ) {
|
if ( null != result ) {
|
||||||
result.retain_sync();
|
result.retain_sync();
|
||||||
|
|
Loading…
Add table
Reference in a new issue