mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
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:
parent
3c32ca6402
commit
f601f2bf57
6 changed files with 128 additions and 97 deletions
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue