use dictmgr in java. This requires jni globals that live across boards being opened and that include a mempool dicts will be allocated out of. Seems to work, and to get ref counts as high as 6 or so before they drop down to one when all boards are closed. (The final is held by the dictmgr which won't give it up until the app itself is GC'd)

This commit is contained in:
Eric House 2014-03-10 19:14:59 -07:00
parent 3c32ca6402
commit f601f2bf57
6 changed files with 128 additions and 97 deletions

View file

@ -67,6 +67,7 @@ COMMON_SRC_FILES += \
$(COMMON_PATH)/tray.c \
$(COMMON_PATH)/dictnry.c \
$(COMMON_PATH)/dictiter.c \
$(COMMON_PATH)/dictmgr.c \
$(COMMON_PATH)/mscore.c \
$(COMMON_PATH)/vtabmgr.c \
$(COMMON_PATH)/strutils.c \

View file

@ -540,7 +540,10 @@ and_dictionary_destroy( DictionaryCtxt* dict )
jobject
and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict )
{
XP_ASSERT( env == ((AndDictionaryCtxt*)dict)->env );
/* XP_ASSERT( env == ((AndDictionaryCtxt*)dict)->env ); */
/* The above is failing now that dictmgr reuses dicts across threads. I
think that's ok, that I didn't have a good reason for having this
assert. But bears watching... */
/* This is cheating: specials will be rep'd as 1,2, etc. But as long as
java code wants to ignore them anyway that's ok. Otherwise need to
@ -563,13 +566,12 @@ and_dictionary_make_empty( MPFORMAL JNIEnv* env, JNIUtilCtxt* jniutil )
dict_super_init( (DictionaryCtxt*)anddict );
MPASSIGN( anddict->super.mpool, mpool );
DictionaryCtxt* result = dict_ref( (DictionaryCtxt*)anddict );
LOG_RETURNF( "%p", result );
return result;
LOG_RETURNF( "%p", anddict );
return (DictionaryCtxt*)anddict;
}
void
makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
makeDicts( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil,
DictionaryCtxt** dictp, PlayerDicts* dicts,
jobjectArray jnames, jobjectArray jdicts, jobjectArray jpaths,
jstring jlang )
@ -586,7 +588,7 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
NULL : (*env)->GetObjectArrayElement( env, jpaths, ii );
if ( NULL != jdict || NULL != jpath ) {
jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii );
dict = makeDict( MPPARM(mpool) env, jniutil, jname, jdict,
dict = makeDict( MPPARM(mpool) env, dictMgr, jniutil, jname, jdict,
jpath, jlang, false );
XP_ASSERT( !!dict );
deleteLocalRefs( env, jdict, jname, DELETE_NO_REF );
@ -603,63 +605,72 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
}
DictionaryCtxt*
makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil, jstring jname,
jbyteArray jbytes, jstring jpath, jstring jlangname, jboolean check )
{
jbyte* bytes = NULL;
jbyteArray byteArray = NULL;
off_t bytesSize = 0;
if ( NULL == jpath ) {
bytesSize = (*env)->GetArrayLength( env, jbytes );
byteArray = (*env)->NewGlobalRef( env, jbytes );
bytes = (*env)->GetByteArrayElements( env, byteArray, NULL );
} else {
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
const char* name = (*env)->GetStringUTFChars( env, jname, NULL );
AndDictionaryCtxt* anddict = (AndDictionaryCtxt*)dmgr_get( dictMgr, name );
struct stat statbuf;
if ( 0 == stat( path, &statbuf ) && 0 < statbuf.st_size ) {
int fd = open( path, O_RDONLY );
if ( fd >= 0 ) {
void* ptr = mmap( NULL, statbuf.st_size, PROT_READ,
MAP_PRIVATE, fd, 0 );
close( fd );
if ( MAP_FAILED != ptr ) {
bytes = ptr;
bytesSize = statbuf.st_size;
if ( NULL == anddict ) {
if ( NULL == jpath ) {
bytesSize = (*env)->GetArrayLength( env, jbytes );
byteArray = (*env)->NewGlobalRef( env, jbytes );
bytes = (*env)->GetByteArrayElements( env, byteArray, NULL );
} else {
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
struct stat statbuf;
if ( 0 == stat( path, &statbuf ) && 0 < statbuf.st_size ) {
int fd = open( path, O_RDONLY );
if ( fd >= 0 ) {
void* ptr = mmap( NULL, statbuf.st_size, PROT_READ,
MAP_PRIVATE, fd, 0 );
close( fd );
if ( MAP_FAILED != ptr ) {
bytes = ptr;
bytesSize = statbuf.st_size;
}
}
}
(*env)->ReleaseStringUTFChars( env, jpath, path );
}
(*env)->ReleaseStringUTFChars( env, jpath, path );
}
AndDictionaryCtxt* anddict = NULL;
if ( NULL != bytes ) {
anddict = (AndDictionaryCtxt*)
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
anddict->bytes = bytes;
anddict->byteArray = byteArray;
anddict->bytesSize = bytesSize;
if ( NULL != bytes ) {
anddict = (AndDictionaryCtxt*)
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
anddict->bytes = bytes;
anddict->byteArray = byteArray;
anddict->bytesSize = bytesSize;
anddict->super.destructor = and_dictionary_destroy;
anddict->super.destructor = and_dictionary_destroy;
/* copy the name */
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
XP_LOGF( "%s(dict=%p); code=%x; name=%s", __func__, anddict,
anddict->dbgid, anddict->super.name );
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
/* copy the name */
anddict->super.name = copyString( mpool, name );
XP_LOGF( "%s(dict=%p); code=%x; name=%s", __func__, anddict,
anddict->dbgid, anddict->super.name );
anddict->super.langName = getStringCopy( MPPARM(mpool)
env, jlangname );
XP_U32 numEdges;
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
bytesSize, &numEdges );
if ( !parses || (check && !checkSanity( &anddict->super,
numEdges ) ) ) {
and_dictionary_destroy( (DictionaryCtxt*)anddict );
anddict = NULL;
XP_U32 numEdges;
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
bytesSize, &numEdges );
if ( !parses || (check && !checkSanity( &anddict->super,
numEdges ) ) ) {
and_dictionary_destroy( (DictionaryCtxt*)anddict );
anddict = NULL;
}
}
dmgr_put( dictMgr, name, &anddict->super );
}
return (DictionaryCtxt*)anddict;
(*env)->ReleaseStringUTFChars( env, jname, name );
DictionaryCtxt* result = dict_ref( (DictionaryCtxt*)anddict ); /* NULL ok */
return result;
} /* makeDict */
#ifdef DEBUG

View file

@ -22,6 +22,7 @@
#define _ANDDICT_H_
#include "dictnry.h"
#include "dictmgr.h"
#include "comtypes.h"
#include "jniutlswrapper.h"
@ -29,11 +30,11 @@ void
dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
XP_U16 nBytes, XP_U16 nFaces );
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
jstring jname, jbyteArray bytes, jstring path,
jstring jlang, jboolean check );
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr,
JNIUtilCtxt* jniutil, jstring jname, jbyteArray bytes,
jstring path, jstring jlang, jboolean check );
void makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
void makeDicts( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil,
DictionaryCtxt** dict, PlayerDicts* dicts, jobjectArray jnames,
jobjectArray jdicts, jobjectArray jpaths, jstring jlang );

View file

@ -392,8 +392,10 @@ and_util_makeEmptyDict( XW_UtilCtxt* uc )
#else
AndGlobals* globals = (AndGlobals*)uc->closure;
AndUtil* andutil = (AndUtil*)uc;
return and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool )
*andutil->env, globals->jniutil );
DictionaryCtxt* result =
and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool )
*andutil->env, globals->jniutil );
return dict_ref( result );
#endif
}

View file

@ -30,6 +30,7 @@
#include "strutils.h"
#include "dictnry.h"
#include "dictiter.h"
#include "dictmgr.h"
#include "utilwrapper.h"
#include "drawwrapper.h"
@ -42,6 +43,7 @@
/* Globals for the whole game */
typedef struct _JNIGlobalState {
JNIEnv* env;
DictMgrCtxt* dictMgr;
MPSLOT
} JNIGlobalState;
@ -54,6 +56,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_initGlobals
#endif
JNIGlobalState* state = (JNIGlobalState*)XP_CALLOC( mpool, sizeof(*state) );
state->env = env;
state->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) );
MPASSIGN( state->mpool, mpool );
LOG_RETURNF( "%p", state );
return (jint)state;
@ -67,6 +70,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_cleanGlobals
if ( 0 != ptr ) {
JNIGlobalState* state = (JNIGlobalState*)ptr;
XP_ASSERT( state->env == env );
dmgr_destroy( state->dictMgr );
#ifdef MEM_DEBUG
MemPoolCtx* mpool = state->mpool;
#endif
@ -374,16 +378,14 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1unref
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname, jstring jpath,
jobject jniu, jboolean check, jobject jinfo )
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jDictBytes,
jstring jname, jstring jpath, jobject jniu, jboolean check, jobject jinfo )
{
jboolean result = false;
#ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make();
#endif
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, check );
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jniutil, jname, jDictBytes, jpath, NULL, check );
if ( NULL != dict ) {
if ( NULL != jinfo ) {
XP_LangCode code = dict_getLangCode( dict );
@ -397,9 +399,6 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
}
destroyJNIUtil( &jniutil );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
return result;
}
@ -531,8 +530,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
DictionaryCtxt* dict;
PlayerDicts dicts;
makeDicts( MPPARM(state->globalJNI->mpool) env, globals->jniutil, &dict, &dicts, j_names,
j_dicts, j_paths, j_lang );
makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr,
globals->jniutil, &dict, &dicts, j_names, j_dicts,
j_paths, j_lang );
#ifdef STUBBED_DICT
if ( !dict ) {
XP_LOGF( "falling back to stubbed dict" );
@ -588,8 +588,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
globals->util = makeUtil( MPPARM(mpool) &state->env,
jutil, globals->gi, globals );
globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu );
makeDicts( MPPARM(state->globalJNI->mpool) env, globals->jniutil, &dict,
&dicts, jdictNames, jdicts, jpaths, jlang );
makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr,
globals->jniutil, &dict, &dicts, jdictNames, jdicts, jpaths,
jlang );
if ( !!jdraw ) {
globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw );
}
@ -1515,8 +1516,10 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1changeDict
jbyteArray jDictBytes, jstring jpath )
{
XWJNI_START_GLOBALS();
DictionaryCtxt* dict = makeDict( MPPARM(state->globalJNI->mpool) env, globals->jniutil,
jname, jDictBytes, jpath, NULL, false );
DictionaryCtxt* dict = makeDict( MPPARM(state->globalJNI->mpool) env,
state->globalJNI->dictMgr,
globals->jniutil, jname, jDictBytes,
jpath, NULL, false );
game_changeDict( MPPARM(mpool) &state->game, globals->gi, dict );
dict_unref( dict );
setJGI( env, jgi, globals->gi );
@ -1637,33 +1640,29 @@ typedef struct _DictIterData {
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname,
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jDictBytes, jstring jname,
jstring jpath, jobject jniu )
{
jint closure = 0;
#ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make();
#endif
DictIterData* data = XP_CALLOC( mpool, sizeof(*data) );
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
DictIterData* data = XP_CALLOC( state->mpool, sizeof(*data) );
data->env = env;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &data->env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, false );
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &data->env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jniutil, jname, jDictBytes, jpath, NULL,
false );
if ( !!dict ) {
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(state->mpool) );
data->jniutil = jniutil;
data->dict = dict;
data->depth = 2;
#ifdef MEM_DEBUG
data->mpool = mpool;
data->mpool = state->mpool;
#endif
closure = (int)data;
} else {
destroyJNIUtil( &jniutil );
XP_FREE( mpool, data );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
XP_FREE( state->mpool, data );
}
return closure;
}
@ -1739,9 +1738,6 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy
freeIndices( data );
vtmgr_destroy( MPPARM(mpool) data->vtMgr );
XP_FREE( mpool, data );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
}
}

View file

@ -52,14 +52,10 @@ public class XwJNI {
}
// @Override
public void finalize()
public void finalize() throws java.lang.Throwable
{
cleanGlobals( m_ptr );
try {
super.finalize();
} catch ( java.lang.Throwable err ){
DbgUtils.logf( "%s", err.toString() );
}
super.finalize();
}
// This needs to be called before the first attempt to use the
@ -329,19 +325,35 @@ public class XwJNI {
{
return m_dictPtr;
}
// @Override
public void finalize() throws java.lang.Throwable
{
release();
super.finalize();
}
}
public static native boolean dict_tilesAreSame( int dict1, int dict2 );
public static native String[] dict_getChars( int dict );
public static native boolean dict_getInfo( byte[] dict, String name,
String path, JNIUtils jniu,
boolean check, DictInfo info );
public static boolean dict_getInfo( byte[] dict, String name,
String path, JNIUtils jniu,
boolean check, DictInfo info )
{
return dict_getInfo( getJNI().m_ptr, dict, name, path, jniu,
check, info );
}
public static native int dict_getTileValue( int dictPtr, int tile );
// Dict iterator
public final static int MAX_COLS_DICT = 15; // from dictiter.h
public static native int dict_iter_init( byte[] dict, String name,
String path, JNIUtils jniu );
public static int dict_iter_init( byte[] dict, String name,
String path, JNIUtils jniu )
{
return dict_iter_init( getJNI().m_ptr, dict, name, path, jniu );
}
public static native void dict_iter_setMinMax( int closure,
int min, int max );
public static native void dict_iter_destroy( int closure );
@ -358,10 +370,18 @@ public class XwJNI {
public static native String base64Encode( byte[] in );
public static native byte[] base64Decode( String in );
// Private methods -- called only here
private static native int initGlobals();
private static native void cleanGlobals( int ptr );
private static native int initJNI( int jniState );
private static native void dict_ref( int dictPtr );
private static native void dict_unref( int dictPtr );
private static native boolean dict_getInfo( int jniState, byte[] dict,
String name, String path,
JNIUtils jniu, boolean check,
DictInfo info );
private static native int dict_iter_init( int jniState, byte[] dict,
String name, String path,
JNIUtils jniu );
}