replace stacked tracking of env with explicit mapping from pthread to

env for that thread to fix occasional assertion failure that indicated
I was using the wrong env occasionally.  I'm not super confident in
this because I've seen the env for a thread change, but that could be
due to reuse of the thread id.
This commit is contained in:
Eric House 2014-10-22 06:58:42 -07:00
parent 046710dd54
commit 3fe3b1724a
10 changed files with 164 additions and 87 deletions

View file

@ -24,6 +24,8 @@
#include "dictnry.h" #include "dictnry.h"
#include "game.h" #include "game.h"
typedef struct _JNIState JNIState;
typedef struct _AndGlobals { typedef struct _AndGlobals {
VTableMgr* vtMgr; VTableMgr* vtMgr;
CurGameInfo* gi; CurGameInfo* gi;
@ -31,7 +33,12 @@ typedef struct _AndGlobals {
XW_UtilCtxt* util; XW_UtilCtxt* util;
struct JNIUtilCtxt* jniutil; struct JNIUtilCtxt* jniutil;
TransportProcs* xportProcs; TransportProcs* xportProcs;
struct JNIState* state; JNIState* state;
} AndGlobals; } AndGlobals;
typedef struct _EnvThreadInfo EnvThreadInfo;
JNIEnv* envForMe( EnvThreadInfo* ti, const char* caller );
#define ENVFORME( ti ) envForMe( (ti), __func__ )
#endif #endif

View file

@ -37,7 +37,7 @@ enum {
typedef struct _AndDraw { typedef struct _AndDraw {
DrawCtxVTable* vtable; DrawCtxVTable* vtable;
JNIEnv** env; EnvThreadInfo* ti;
jobject jdraw; /* global ref; free it! */ jobject jdraw; /* global ref; free it! */
XP_LangCode curLang; XP_LangCode curLang;
jobject jCache[JCACHE_COUNT]; jobject jCache[JCACHE_COUNT];
@ -48,7 +48,7 @@ typedef struct _AndDraw {
static jobject static jobject
makeJRect( AndDraw* draw, int indx, const XP_Rect* rect ) makeJRect( AndDraw* draw, int indx, const XP_Rect* rect )
{ {
JNIEnv* env = *draw->env; JNIEnv* env = ENVFORME( draw->ti );
jobject robj = draw->jCache[indx]; jobject robj = draw->jCache[indx];
int right = rect->left + rect->width; int right = rect->left + rect->width;
int bottom = rect->top + rect->height; int bottom = rect->top + rect->height;
@ -87,7 +87,7 @@ static jobject
makeJRects( AndDraw* draw, int indx, XP_U16 nPlayers, const XP_Rect rects[] ) makeJRects( AndDraw* draw, int indx, XP_U16 nPlayers, const XP_Rect rects[] )
{ {
XP_U16 ii; XP_U16 ii;
JNIEnv* env = *draw->env; JNIEnv* env = ENVFORME( draw->ti );
jobject jrects = draw->jCache[indx]; jobject jrects = draw->jCache[indx];
if ( !jrects ) { if ( !jrects ) {
jclass rclass = (*env)->FindClass( env, "android/graphics/Rect"); jclass rclass = (*env)->FindClass( env, "android/graphics/Rect");
@ -122,7 +122,7 @@ static jobject
makeDSIs( AndDraw* draw, int indx, XP_U16 nPlayers, const DrawScoreInfo dsis[] ) makeDSIs( AndDraw* draw, int indx, XP_U16 nPlayers, const DrawScoreInfo dsis[] )
{ {
XP_U16 ii; XP_U16 ii;
JNIEnv* env = *draw->env; JNIEnv* env = ENVFORME( draw->ti );
jobject dsiobjs = draw->jCache[indx]; jobject dsiobjs = draw->jCache[indx];
if ( !dsiobjs ) { if ( !dsiobjs ) {
@ -164,7 +164,7 @@ makeDSIs( AndDraw* draw, int indx, XP_U16 nPlayers, const DrawScoreInfo dsis[] )
static jobject static jobject
makeDSI( AndDraw* draw, int indx, const DrawScoreInfo* dsi ) makeDSI( AndDraw* draw, int indx, const DrawScoreInfo* dsi )
{ {
JNIEnv* env = *draw->env; JNIEnv* env = ENVFORME( draw->ti );
jobject dsiobj = draw->jCache[indx]; jobject dsiobj = draw->jCache[indx];
if ( !dsiobj ) { if ( !dsiobj ) {
@ -193,7 +193,7 @@ makeDSI( AndDraw* draw, int indx, const DrawScoreInfo* dsi )
#define DRAW_CBK_HEADER(nam,sig) \ #define DRAW_CBK_HEADER(nam,sig) \
AndDraw* draw = (AndDraw*)dctx; \ AndDraw* draw = (AndDraw*)dctx; \
JNIEnv* env = *draw->env; \ JNIEnv* env = ENVFORME( draw->ti ); \
XP_ASSERT( !!draw->jdraw ); \ XP_ASSERT( !!draw->jdraw ); \
jmethodID mid = getMethodID( env, draw->jdraw, nam, sig ); jmethodID mid = getMethodID( env, draw->jdraw, nam, sig );
@ -600,15 +600,15 @@ draw_doNothing( DrawCtx* dctx, ... )
} /* draw_doNothing */ } /* draw_doNothing */
DrawCtx* DrawCtx*
makeDraw( MPFORMAL JNIEnv** envp, jobject jdraw ) makeDraw( MPFORMAL EnvThreadInfo* ti, jobject jdraw )
{ {
AndDraw* draw = (AndDraw*)XP_CALLOC( mpool, sizeof(*draw) ); AndDraw* draw = (AndDraw*)XP_CALLOC( mpool, sizeof(*draw) );
JNIEnv* env = *envp; JNIEnv* env = ENVFORME( ti );
draw->vtable = XP_MALLOC( mpool, sizeof(*draw->vtable) ); draw->vtable = XP_MALLOC( mpool, sizeof(*draw->vtable) );
if ( NULL != jdraw ) { if ( NULL != jdraw ) {
draw->jdraw = (*env)->NewGlobalRef( env, jdraw ); draw->jdraw = (*env)->NewGlobalRef( env, jdraw );
} }
draw->env = envp; draw->ti = ti;
MPASSIGN( draw->mpool, mpool ); MPASSIGN( draw->mpool, mpool );
int ii; int ii;
@ -659,7 +659,7 @@ destroyDraw( DrawCtx** dctx )
{ {
if ( !!*dctx ) { if ( !!*dctx ) {
AndDraw* draw = (AndDraw*)*dctx; AndDraw* draw = (AndDraw*)*dctx;
JNIEnv* env = *draw->env; JNIEnv* env = ENVFORME( draw->ti );
if ( NULL != draw->jdraw ) { if ( NULL != draw->jdraw ) {
(*env)->DeleteGlobalRef( env, draw->jdraw ); (*env)->DeleteGlobalRef( env, draw->jdraw );
} }

View file

@ -25,7 +25,9 @@
#include "draw.h" #include "draw.h"
DrawCtx* makeDraw( MPFORMAL JNIEnv** env, jobject j_draw ); #include "andglobals.h"
DrawCtx* makeDraw( MPFORMAL EnvThreadInfo* ti, jobject j_draw );
void destroyDraw( DrawCtx** dctx ); void destroyDraw( DrawCtx** dctx );

View file

@ -24,17 +24,17 @@
struct JNIUtilCtxt { struct JNIUtilCtxt {
JNIEnv** envp; EnvThreadInfo* ti;
jobject jjniutil; jobject jjniutil;
MPSLOT; MPSLOT;
}; };
JNIUtilCtxt* JNIUtilCtxt*
makeJNIUtil( MPFORMAL JNIEnv** envp, jobject jniutls ) makeJNIUtil( MPFORMAL EnvThreadInfo* ti, jobject jniutls )
{ {
JNIUtilCtxt* ctxt = (JNIUtilCtxt*)XP_CALLOC( mpool, sizeof( *ctxt ) ); JNIUtilCtxt* ctxt = (JNIUtilCtxt*)XP_CALLOC( mpool, sizeof( *ctxt ) );
JNIEnv* env = *envp; ctxt->ti = ti;
ctxt->envp = envp; JNIEnv* env = ENVFORME( ti );
ctxt->jjniutil = (*env)->NewGlobalRef( env, jniutls ); ctxt->jjniutil = (*env)->NewGlobalRef( env, jniutls );
MPASSIGN( ctxt->mpool, mpool ); MPASSIGN( ctxt->mpool, mpool );
return ctxt; return ctxt;
@ -45,7 +45,7 @@ destroyJNIUtil( JNIUtilCtxt** ctxtp )
{ {
JNIUtilCtxt* ctxt = *ctxtp; JNIUtilCtxt* ctxt = *ctxtp;
if ( !!ctxt ) { if ( !!ctxt ) {
JNIEnv* env = *ctxt->envp; JNIEnv* env = ENVFORME( ctxt->ti );
(*env)->DeleteGlobalRef( env, ctxt->jjniutil ); (*env)->DeleteGlobalRef( env, ctxt->jjniutil );
XP_FREE( ctxt->mpool, ctxt ); XP_FREE( ctxt->mpool, ctxt );
*ctxtp = NULL; *ctxtp = NULL;
@ -59,7 +59,7 @@ and_util_makeJBitmap( JNIUtilCtxt* jniutil, int nCols, int nRows,
const jboolean* colors ) const jboolean* colors )
{ {
jobject bitmap; jobject bitmap;
JNIEnv* env = *jniutil->envp; JNIEnv* env = ENVFORME( jniutil->ti );
jmethodID mid jmethodID mid
= getMethodID( env, jniutil->jjniutil, "makeBitmap", = getMethodID( env, jniutil->jjniutil, "makeBitmap",
"(II[Z)Landroid/graphics/drawable/BitmapDrawable;" ); "(II[Z)Landroid/graphics/drawable/BitmapDrawable;" );
@ -79,7 +79,7 @@ and_util_splitFaces( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len,
XP_Bool isUTF8 ) XP_Bool isUTF8 )
{ {
jobject strarray = NULL; jobject strarray = NULL;
JNIEnv* env = *jniutil->envp; JNIEnv* env = ENVFORME( jniutil->ti );
jmethodID mid jmethodID mid
= getMethodID( env, jniutil->jjniutil, "splitFaces", = getMethodID( env, jniutil->jjniutil, "splitFaces",
"([BZ)[[Ljava/lang/String;" ); "([BZ)[[Ljava/lang/String;" );
@ -96,7 +96,7 @@ jstring
and_util_getMD5SumForDict( JNIUtilCtxt* jniutil, const XP_UCHAR* name, and_util_getMD5SumForDict( JNIUtilCtxt* jniutil, const XP_UCHAR* name,
const XP_U8* bytes, jsize len ) const XP_U8* bytes, jsize len )
{ {
JNIEnv* env = *jniutil->envp; JNIEnv* env = ENVFORME( jniutil->ti );
jmethodID mid = getMethodID( env, jniutil->jjniutil, "getMD5SumFor", jmethodID mid = getMethodID( env, jniutil->jjniutil, "getMD5SumFor",
"(Ljava/lang/String;[B)Ljava/lang/String;" ); "(Ljava/lang/String;[B)Ljava/lang/String;" );
jstring jname = (*env)->NewStringUTF( env, name ); jstring jname = (*env)->NewStringUTF( env, name );
@ -112,7 +112,7 @@ and_util_getMD5SumForDict( JNIUtilCtxt* jniutil, const XP_UCHAR* name,
jstring jstring
and_util_getMD5SumForBytes( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len ) and_util_getMD5SumForBytes( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len )
{ {
JNIEnv* env = *jniutil->envp; JNIEnv* env = ENVFORME( jniutil->ti );
jmethodID mid = getMethodID( env, jniutil->jjniutil, "getMD5SumFor", jmethodID mid = getMethodID( env, jniutil->jjniutil, "getMD5SumFor",
"([B)Ljava/lang/String;" ); "([B)Ljava/lang/String;" );

View file

@ -28,7 +28,7 @@
typedef struct JNIUtilCtxt JNIUtilCtxt; typedef struct JNIUtilCtxt JNIUtilCtxt;
JNIUtilCtxt* makeJNIUtil( MPFORMAL JNIEnv** env, jobject jniutls ); JNIUtilCtxt* makeJNIUtil( MPFORMAL EnvThreadInfo* ti, jobject jniutls );
void destroyJNIUtil( JNIUtilCtxt** jniu ); void destroyJNIUtil( JNIUtilCtxt** jniu );
jobject and_util_makeJBitmap( JNIUtilCtxt* jniu, int nCols, int nRows, jobject and_util_makeJBitmap( JNIUtilCtxt* jniu, int nCols, int nRows,

View file

@ -35,7 +35,7 @@ typedef struct _TimerStorage {
typedef struct _AndUtil { typedef struct _AndUtil {
XW_UtilCtxt util; XW_UtilCtxt util;
JNIEnv** env; EnvThreadInfo* ti;
jobject jutil; /* global ref to object implementing XW_UtilCtxt */ jobject jutil; /* global ref to object implementing XW_UtilCtxt */
TimerStorage timerStorage[NUM_TIMERS_PLUS_ONE]; TimerStorage timerStorage[NUM_TIMERS_PLUS_ONE];
XP_UCHAR* userStrings[N_AND_USER_STRINGS]; XP_UCHAR* userStrings[N_AND_USER_STRINGS];
@ -70,7 +70,7 @@ and_util_makeStreamFromAddr( XW_UtilCtxt* uc, XP_PlayerAddr channelNo )
#define UTIL_CBK_HEADER(nam,sig) \ #define UTIL_CBK_HEADER(nam,sig) \
AndUtil* util = (AndUtil*)uc; \ AndUtil* util = (AndUtil*)uc; \
JNIEnv* env = *util->env; \ JNIEnv* env = ENVFORME( util->ti ); \
if ( NULL != util->jutil ) { \ if ( NULL != util->jutil ) { \
jmethodID mid = getMethodID( env, util->jutil, nam, sig ) jmethodID mid = getMethodID( env, util->jutil, nam, sig )
@ -376,7 +376,7 @@ XP_U32
and_util_getCurSeconds( XW_UtilCtxt* uc ) and_util_getCurSeconds( XW_UtilCtxt* uc )
{ {
AndUtil* andutil = (AndUtil*)uc; AndUtil* andutil = (AndUtil*)uc;
XP_U32 curSeconds = getCurSeconds( *andutil->env ); XP_U32 curSeconds = getCurSeconds( ENVFORME( andutil->ti ) );
/* struct timeval tv; */ /* struct timeval tv; */
/* gettimeofday( &tv, NULL ); */ /* gettimeofday( &tv, NULL ); */
/* XP_LOGF( "%s: %d vs %d", __func__, (int)tv.tv_sec, (int)curSeconds ); */ /* XP_LOGF( "%s: %d vs %d", __func__, (int)tv.tv_sec, (int)curSeconds ); */
@ -394,7 +394,7 @@ and_util_makeEmptyDict( XW_UtilCtxt* uc )
AndUtil* andutil = (AndUtil*)uc; AndUtil* andutil = (AndUtil*)uc;
DictionaryCtxt* result = DictionaryCtxt* result =
and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool ) and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool )
*andutil->env, globals->jniutil ); ENVFORME( andutil->ti ), globals->jniutil );
return dict_ref( result ); return dict_ref( result );
#endif #endif
} }
@ -637,7 +637,7 @@ static XP_UCHAR*
and_util_md5sum( XW_UtilCtxt* uc, const XP_U8* ptr, XP_U16 len ) and_util_md5sum( XW_UtilCtxt* uc, const XP_U8* ptr, XP_U16 len )
{ {
AndUtil* util = (AndUtil*)uc; AndUtil* util = (AndUtil*)uc;
JNIEnv* env = *util->env; JNIEnv* env = ENVFORME( util->ti );
AndGlobals* globals = (AndGlobals*)uc->closure; AndGlobals* globals = (AndGlobals*)uc->closure;
struct JNIUtilCtxt* jniutil = globals->jniutil; struct JNIUtilCtxt* jniutil = globals->jniutil;
jstring jsum = and_util_getMD5SumForBytes( jniutil, ptr, len ); jstring jsum = and_util_getMD5SumForBytes( jniutil, ptr, len );
@ -649,13 +649,13 @@ and_util_md5sum( XW_UtilCtxt* uc, const XP_U8* ptr, XP_U16 len )
XW_UtilCtxt* XW_UtilCtxt*
makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi, makeUtil( MPFORMAL EnvThreadInfo* ti, jobject jutil, CurGameInfo* gi,
AndGlobals* closure ) AndGlobals* closure )
{ {
AndUtil* util = (AndUtil*)XP_CALLOC( mpool, sizeof(*util) ); AndUtil* util = (AndUtil*)XP_CALLOC( mpool, sizeof(*util) );
UtilVtable* vtable = (UtilVtable*)XP_CALLOC( mpool, sizeof(*vtable) ); UtilVtable* vtable = (UtilVtable*)XP_CALLOC( mpool, sizeof(*vtable) );
util->env = envp; util->ti = ti;
JNIEnv* env = *envp; JNIEnv* env = ENVFORME( util->ti );
if ( NULL != jutil ) { if ( NULL != jutil ) {
util->jutil = (*env)->NewGlobalRef( env, jutil ); util->jutil = (*env)->NewGlobalRef( env, jutil );
} }
@ -743,7 +743,7 @@ void
destroyUtil( XW_UtilCtxt** utilc ) destroyUtil( XW_UtilCtxt** utilc )
{ {
AndUtil* util = (AndUtil*)*utilc; AndUtil* util = (AndUtil*)*utilc;
JNIEnv *env = *util->env; JNIEnv* env = ENVFORME( util->ti );
int ii; int ii;
for ( ii = 0; ii < VSIZE(util->userStrings); ++ii ) { for ( ii = 0; ii < VSIZE(util->userStrings); ++ii ) {

View file

@ -27,7 +27,7 @@
#include "util.h" #include "util.h"
#include "andglobals.h" #include "andglobals.h"
XW_UtilCtxt* makeUtil( MPFORMAL JNIEnv** env, jobject j_util, XW_UtilCtxt* makeUtil( MPFORMAL EnvThreadInfo* ti, jobject j_util,
CurGameInfo* gi, AndGlobals* globals ); CurGameInfo* gi, AndGlobals* globals );
void destroyUtil( XW_UtilCtxt** util ); void destroyUtil( XW_UtilCtxt** util );

View file

@ -24,7 +24,7 @@
typedef struct _AndTransportProcs { typedef struct _AndTransportProcs {
TransportProcs tp; TransportProcs tp;
JNIEnv** envp; EnvThreadInfo* ti;
jobject jxport; jobject jxport;
MPSLOT MPSLOT
} AndTransportProcs; } AndTransportProcs;
@ -56,7 +56,7 @@ and_xport_getFlags( void* closure )
jint result = 0; jint result = 0;
AndTransportProcs* aprocs = (AndTransportProcs*)closure; AndTransportProcs* aprocs = (AndTransportProcs*)closure;
if ( NULL != aprocs->jxport ) { if ( NULL != aprocs->jxport ) {
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
const char* sig = "()I"; const char* sig = "()I";
jmethodID mid = getMethodID( env, aprocs->jxport, "getFlags", sig ); jmethodID mid = getMethodID( env, aprocs->jxport, "getFlags", sig );
@ -73,7 +73,7 @@ and_xport_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
LOG_FUNC(); LOG_FUNC();
AndTransportProcs* aprocs = (AndTransportProcs*)closure; AndTransportProcs* aprocs = (AndTransportProcs*)closure;
if ( NULL != aprocs->jxport ) { if ( NULL != aprocs->jxport ) {
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
const char* sig = "([BL" PKG_PATH("jni/CommsAddrRec") ";I)I"; const char* sig = "([BL" PKG_PATH("jni/CommsAddrRec") ";I)I";
jmethodID mid = getMethodID( env, aprocs->jxport, "transportSend", sig ); jmethodID mid = getMethodID( env, aprocs->jxport, "transportSend", sig );
@ -94,7 +94,7 @@ and_xport_relayStatus( void* closure, CommsRelayState newState )
{ {
AndTransportProcs* aprocs = (AndTransportProcs*)closure; AndTransportProcs* aprocs = (AndTransportProcs*)closure;
if ( NULL != aprocs->jxport ) { if ( NULL != aprocs->jxport ) {
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
const char* sig = "(L" PKG_PATH("jni/TransportProcs$CommsRelayState") ";)V"; const char* sig = "(L" PKG_PATH("jni/TransportProcs$CommsRelayState") ";)V";
jmethodID mid = getMethodID( env, aprocs->jxport, "relayStatus", sig ); jmethodID mid = getMethodID( env, aprocs->jxport, "relayStatus", sig );
@ -111,7 +111,7 @@ and_xport_relayConnd( void* closure, XP_UCHAR* const room, XP_Bool reconnect,
{ {
AndTransportProcs* aprocs = (AndTransportProcs*)closure; AndTransportProcs* aprocs = (AndTransportProcs*)closure;
if ( NULL != aprocs->jxport ) { if ( NULL != aprocs->jxport ) {
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
const char* sig = "(Ljava/lang/String;IZI)V"; const char* sig = "(Ljava/lang/String;IZI)V";
jmethodID mid = getMethodID( env, aprocs->jxport, "relayConnd", sig ); jmethodID mid = getMethodID( env, aprocs->jxport, "relayConnd", sig );
@ -129,7 +129,7 @@ and_xport_sendNoConn( const XP_U8* buf, XP_U16 len,
jboolean result = false; jboolean result = false;
AndTransportProcs* aprocs = (AndTransportProcs*)closure; AndTransportProcs* aprocs = (AndTransportProcs*)closure;
if ( NULL != aprocs && NULL != aprocs->jxport ) { if ( NULL != aprocs && NULL != aprocs->jxport ) {
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
const char* sig = "([BLjava/lang/String;)Z"; const char* sig = "([BLjava/lang/String;)Z";
jmethodID mid = getMethodID( env, aprocs->jxport, jmethodID mid = getMethodID( env, aprocs->jxport,
@ -148,7 +148,7 @@ and_xport_relayError( void* closure, XWREASON relayErr )
{ {
AndTransportProcs* aprocs = (AndTransportProcs*)closure; AndTransportProcs* aprocs = (AndTransportProcs*)closure;
if ( NULL != aprocs->jxport ) { if ( NULL != aprocs->jxport ) {
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
jmethodID mid; jmethodID mid;
const char* sig = const char* sig =
"(L" PKG_PATH("jni/TransportProcs$XWRELAY_ERROR") ";)V"; "(L" PKG_PATH("jni/TransportProcs$XWRELAY_ERROR") ";)V";
@ -163,16 +163,16 @@ and_xport_relayError( void* closure, XWREASON relayErr )
} }
TransportProcs* TransportProcs*
makeXportProcs( MPFORMAL JNIEnv** envp, jobject jxport ) makeXportProcs( MPFORMAL EnvThreadInfo* ti, jobject jxport )
{ {
AndTransportProcs* aprocs = NULL; AndTransportProcs* aprocs = NULL;
JNIEnv* env = *envp; JNIEnv* env = ENVFORME( ti );
aprocs = (AndTransportProcs*)XP_CALLOC( mpool, sizeof(*aprocs) ); aprocs = (AndTransportProcs*)XP_CALLOC( mpool, sizeof(*aprocs) );
if ( NULL != jxport ) { if ( NULL != jxport ) {
aprocs->jxport = (*env)->NewGlobalRef( env, jxport ); aprocs->jxport = (*env)->NewGlobalRef( env, jxport );
} }
aprocs->envp = envp; aprocs->ti = ti;
MPASSIGN( aprocs->mpool, mpool ); MPASSIGN( aprocs->mpool, mpool );
#ifdef COMMS_XPORT_FLAGSPROC #ifdef COMMS_XPORT_FLAGSPROC
@ -192,7 +192,7 @@ void
destroyXportProcs( TransportProcs** xport ) destroyXportProcs( TransportProcs** xport )
{ {
AndTransportProcs* aprocs = (AndTransportProcs*)*xport; AndTransportProcs* aprocs = (AndTransportProcs*)*xport;
JNIEnv* env = *aprocs->envp; JNIEnv* env = ENVFORME( aprocs->ti );
if ( NULL != aprocs->jxport ) { if ( NULL != aprocs->jxport ) {
(*env)->DeleteGlobalRef( env, aprocs->jxport ); (*env)->DeleteGlobalRef( env, aprocs->jxport );
} }

View file

@ -23,9 +23,12 @@
#include <jni.h> #include <jni.h>
#include "andglobals.h"
#include "comms.h" #include "comms.h"
TransportProcs* makeXportProcs( MPFORMAL JNIEnv** env, jobject jxport ); TransportProcs* makeXportProcs( MPFORMAL EnvThreadInfo* ti, jobject jxport );
void destroyXportProcs( TransportProcs** xport ); void destroyXportProcs( TransportProcs** xport );
#endif #endif

View file

@ -19,6 +19,7 @@
*/ */
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
#include <pthread.h>
#include <jni.h> #include <jni.h>
#include <android/log.h> #include <android/log.h>
@ -37,16 +38,97 @@
#include "xportwrapper.h" #include "xportwrapper.h"
#include "anddict.h" #include "anddict.h"
#include "andutils.h" #include "andutils.h"
#include "andglobals.h"
#include "jniutlswrapper.h" #include "jniutlswrapper.h"
#include "paths.h" #include "paths.h"
typedef struct _EnvThreadEntry {
JNIEnv* env;
pthread_t owner;
} EnvThreadEntry;
#define MAX_ENV_THREADS 10
struct _EnvThreadInfo {
pthread_mutex_t mtxThreads;
EnvThreadEntry entries[MAX_ENV_THREADS];
XP_U16 nMaps;
};
/* Globals for the whole game */ /* Globals for the whole game */
typedef struct _JNIGlobalState { typedef struct _JNIGlobalState {
JNIEnv* env; EnvThreadInfo ti;
DictMgrCtxt* dictMgr; DictMgrCtxt* dictMgr;
MPSLOT MPSLOT
} JNIGlobalState; } JNIGlobalState;
static void
map_init( EnvThreadInfo* ti )
{
pthread_mutex_init( &ti->mtxThreads, NULL );
}
static void
map_destroy( EnvThreadInfo* ti )
{
// XP_ASSERT( 0 == ti->nMaps );
XP_LOGF( "%s: had %d threads max", __func__, ti->nMaps );
pthread_mutex_destroy( &ti->mtxThreads );
}
static void
map_thread( EnvThreadInfo* ti, JNIEnv* env, const char* proc )
{
pthread_t self = pthread_self();
pthread_mutex_lock( &ti->mtxThreads );
XP_Bool found = false;
for ( int ii = 0; !found && ii < ti->nMaps; ++ii ) {
EnvThreadEntry* entry = &ti->entries[ii];
found = self == entry->owner;
if ( found ) {
if ( env != entry->env ) {
/* this DOES happen!!! */
XP_LOGF( "%s: replacing env %p with env %p for thread %x",
__func__, entry->env, env, (int)self );
entry->env = env;
}
}
}
if ( !found ) {
EnvThreadEntry* entry = &ti->entries[ti->nMaps++];
entry->owner = self;
entry->env = env;
XP_LOGF( "%s: mapped env %p to thread %x", __func__, env, (int)self );
XP_ASSERT( ti->nMaps < MAX_ENV_THREADS );
}
pthread_mutex_unlock( &ti->mtxThreads );
}
JNIEnv*
envForMe( EnvThreadInfo* ti, const char* caller )
{
JNIEnv* result = NULL;
pthread_t self = pthread_self();
pthread_mutex_lock( &ti->mtxThreads );
for ( int ii = 0; ii < ti->nMaps; ++ii ) {
if ( self == ti->entries[ii].owner ) {
result = ti->entries[ii].env;
break;
}
}
pthread_mutex_unlock( &ti->mtxThreads );
if( !result ) {
XP_LOGF( "no env for %s (thread %x in %d entries)", caller,
(int)self, ti->nMaps );
XP_ASSERT(0);
}
return result;
}
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_initGlobals Java_org_eehouse_android_xw4_jni_XwJNI_initGlobals
( JNIEnv* env, jclass C ) ( JNIEnv* env, jclass C )
@ -55,7 +137,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_initGlobals
MemPoolCtx* mpool = mpool_make(); MemPoolCtx* mpool = mpool_make();
#endif #endif
JNIGlobalState* state = (JNIGlobalState*)XP_CALLOC( mpool, sizeof(*state) ); JNIGlobalState* state = (JNIGlobalState*)XP_CALLOC( mpool, sizeof(*state) );
state->env = env; map_init( &state->ti );
state->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) ); state->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) );
MPASSIGN( state->mpool, mpool ); MPASSIGN( state->mpool, mpool );
LOG_RETURNF( "%p", state ); LOG_RETURNF( "%p", state );
@ -69,11 +151,12 @@ Java_org_eehouse_android_xw4_jni_XwJNI_cleanGlobals
LOG_FUNC(); LOG_FUNC();
if ( 0 != ptr ) { if ( 0 != ptr ) {
JNIGlobalState* state = (JNIGlobalState*)ptr; JNIGlobalState* state = (JNIGlobalState*)ptr;
XP_ASSERT( state->env == env ); XP_ASSERT( ENVFORME(&state->ti) == env );
dmgr_destroy( state->dictMgr ); dmgr_destroy( state->dictMgr );
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
MemPoolCtx* mpool = state->mpool; MemPoolCtx* mpool = state->mpool;
#endif #endif
map_destroy( &state->ti );
XP_FREE( mpool, state ); XP_FREE( mpool, state );
mpool_destroy( mpool ); mpool_destroy( mpool );
} }
@ -386,9 +469,10 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
{ {
jboolean result = false; jboolean result = false;
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr; JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &env, jniu ); JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &state->ti, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr, DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jniutil, jname, jDictBytes, jpath, NULL, check ); jniutil, jname, jDictBytes, jpath,
NULL, check );
if ( NULL != dict ) { if ( NULL != dict ) {
if ( NULL != jinfo ) { if ( NULL != jinfo ) {
XP_LangCode code = dict_getLangCode( dict ); XP_LangCode code = dict_getLangCode( dict );
@ -435,9 +519,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
return dict_getTileValue( (DictionaryCtxt*)dictPtr, tile ); return dict_getTileValue( (DictionaryCtxt*)dictPtr, tile );
} }
typedef struct _JNIState { struct _JNIState {
XWGame game; XWGame game;
JNIEnv* env;
JNIGlobalState* globalJNI; JNIGlobalState* globalJNI;
AndGlobals globals; AndGlobals globals;
XP_U16 curSaveCount; XP_U16 curSaveCount;
@ -446,38 +529,22 @@ typedef struct _JNIState {
const char* envSetterFunc; const char* envSetterFunc;
#endif #endif
MPSLOT MPSLOT
} JNIState; };
#ifdef DEBUG
# define CHECK_ENV() \
if ( state->env != 0 && state->env != env ) { \
XP_LOGF( "ERROR: %s trying to set env when %s still has it", \
__func__, state->envSetterFunc ); \
XP_ASSERT( state->env == 0 || state->env == env ); \
} \
state->envSetterFunc = __func__; \
#else
# define CHECK_ENV()
#endif
#define XWJNI_START() { \ #define XWJNI_START() { \
XP_ASSERT( 0 != gamePtr ); \ XP_ASSERT( 0 != gamePtr ); \
JNIState* state = (JNIState*)gamePtr; \ JNIState* state = (JNIState*)gamePtr; \
MPSLOT; \ MPSLOT; \
MPASSIGN( mpool, state->mpool); \ MPASSIGN( mpool, state->mpool); \
/* if reentrant must be from same thread */ \ XP_ASSERT( !!state->globalJNI ); \
CHECK_ENV(); \ map_thread( &state->globalJNI->ti, env, __func__ ); \
JNIEnv* _oldEnv = state->env; \
state->env = env;
#define XWJNI_START_GLOBALS() \ #define XWJNI_START_GLOBALS() \
XWJNI_START() \ XWJNI_START() \
AndGlobals* globals = &state->globals; \ AndGlobals* globals = &state->globals; \
#define XWJNI_END() \ #define XWJNI_END() \
state->env = _oldEnv; \ } \
}
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_initJNI Java_org_eehouse_android_xw4_jni_XwJNI_initJNI
@ -493,7 +560,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_initJNI
JNIState* state = (JNIState*)XP_CALLOC( mpool, sizeof(*state) ); JNIState* state = (JNIState*)XP_CALLOC( mpool, sizeof(*state) );
state->globalJNI = (JNIGlobalState*)jniGlobalPtr; state->globalJNI = (JNIGlobalState*)jniGlobalPtr;
AndGlobals* globals = &state->globals; AndGlobals* globals = &state->globals;
globals->state = (struct JNIState*)state; globals->state = (JNIState*)state;
MPASSIGN( state->mpool, mpool ); MPASSIGN( state->mpool, mpool );
globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool)); globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool));
@ -511,17 +578,18 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
jstring j_lang ) jstring j_lang )
{ {
XWJNI_START_GLOBALS(); XWJNI_START_GLOBALS();
EnvThreadInfo* ti = &state->globalJNI->ti;
CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi ); CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi );
globals->gi = gi; globals->gi = gi;
globals->util = makeUtil( MPPARM(mpool) &state->env, j_util, gi, globals->util = makeUtil( MPPARM(mpool) ti, j_util, gi,
globals ); globals );
globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu ); globals->jniutil = makeJNIUtil( MPPARM(mpool) ti, jniu );
DrawCtx* dctx = NULL; DrawCtx* dctx = NULL;
if ( !!j_draw ) { if ( !!j_draw ) {
dctx = makeDraw( MPPARM(mpool) &state->env, j_draw ); dctx = makeDraw( MPPARM(mpool) ti, j_draw );
} }
globals->dctx = dctx; globals->dctx = dctx;
globals->xportProcs = makeXportProcs( MPPARM(mpool) &state->env, j_procs ); globals->xportProcs = makeXportProcs( MPPARM(mpool) ti, j_procs );
CommonPrefs cp; CommonPrefs cp;
loadCommonPrefs( env, &cp, j_cp ); loadCommonPrefs( env, &cp, j_cp );
@ -559,8 +627,6 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose
destroyGI( MPPARM(mpool) &globals->gi ); destroyGI( MPPARM(mpool) &globals->gi );
JNIEnv* oldEnv = state->env;
state->env = env;
game_dispose( &state->game ); game_dispose( &state->game );
destroyDraw( &globals->dctx ); destroyDraw( &globals->dctx );
@ -569,7 +635,6 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose
destroyJNIUtil( &globals->jniutil ); destroyJNIUtil( &globals->jniutil );
vtmgr_destroy( MPPARM(mpool) globals->vtMgr ); vtmgr_destroy( MPPARM(mpool) globals->vtMgr );
state->env = oldEnv;
XP_FREE( mpool, state ); XP_FREE( mpool, state );
mpool_destroy( mpool ); mpool_destroy( mpool );
} /* game_dispose */ } /* game_dispose */
@ -585,18 +650,18 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
DictionaryCtxt* dict; DictionaryCtxt* dict;
PlayerDicts dicts; PlayerDicts dicts;
XWJNI_START_GLOBALS(); XWJNI_START_GLOBALS();
EnvThreadInfo* ti = &state->globalJNI->ti;
globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) ); globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) );
globals->util = makeUtil( MPPARM(mpool) &state->env, globals->util = makeUtil( MPPARM(mpool) ti, jutil, globals->gi, globals);
jutil, globals->gi, globals ); globals->jniutil = makeJNIUtil( MPPARM(mpool) ti, jniu );
globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu );
makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr, makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr,
globals->jniutil, &dict, &dicts, jdictNames, jdicts, jpaths, globals->jniutil, &dict, &dicts, jdictNames, jdicts, jpaths,
jlang ); jlang );
if ( !!jdraw ) { if ( !!jdraw ) {
globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw ); globals->dctx = makeDraw( MPPARM(mpool) ti, jdraw );
} }
globals->xportProcs = makeXportProcs( MPPARM(mpool) &state->env, jprocs ); globals->xportProcs = makeXportProcs( MPPARM(mpool) ti, jprocs );
XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env, XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env,
globals->vtMgr, jstream ); globals->vtMgr, jstream );
@ -673,7 +738,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1setDraw
{ {
XWJNI_START_GLOBALS(); XWJNI_START_GLOBALS();
DrawCtx* newDraw = makeDraw( MPPARM(mpool) &state->env, jdraw ); DrawCtx* newDraw = makeDraw( MPPARM(mpool) &state->globalJNI->ti, jdraw );
board_setDraw( state->game.board, newDraw ); board_setDraw( state->game.board, newDraw );
destroyDraw( &globals->dctx ); destroyDraw( &globals->dctx );
@ -1664,7 +1729,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr; JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
DictIterData* data = XP_CALLOC( state->mpool, sizeof(*data) ); DictIterData* data = XP_CALLOC( state->mpool, sizeof(*data) );
data->env = env; data->env = env;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &data->env, jniu ); JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &state->ti, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr, DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jniutil, jname, jDictBytes, jpath, NULL, jniutil, jname, jDictBytes, jpath, NULL,
false ); false );