pool acks and send using a timer (untested on Android)

This commit is contained in:
Eric House 2024-08-19 06:56:33 -07:00
parent faf398790c
commit c45638e037
4 changed files with 80 additions and 45 deletions

View file

@ -29,6 +29,7 @@
#include "nli.h" #include "nli.h"
#include "dbgutil.h" #include "dbgutil.h"
#include "timers.h" #include "timers.h"
#include "xwmutex.h"
#ifdef DEBUG #ifdef DEBUG
# define MAGIC_INITED 0x8283413F # define MAGIC_INITED 0x8283413F
@ -73,7 +74,13 @@ typedef struct _DevCtxt {
XP_U16 devCount; XP_U16 devCount;
WSData* webSendData; WSData* webSendData;
XP_U32 mWebSendKey; XP_U32 mWebSendKey;
pthread_mutex_t webSendMutex; MutexState webSendMutex;
struct {
MutexState mutex;
cJSON* msgs; /* pending acks saved here */
TimerKey key;
} ackTimer;
PhoniesDataCodes* pd; PhoniesDataCodes* pd;
@ -538,41 +545,64 @@ dispatchMsgs( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U8 proto, XWStreamCtxt* stream,
} }
} }
static void
onAckSendTimer( void* closure, XWEnv xwe, XP_Bool fired )
{
XP_LOGFF( "(fired: %s)", boolToStr(fired) );
XW_DUtilCtxt* dutil = (XW_DUtilCtxt*)closure;
DevCtxt* dc = load( dutil, xwe );
cJSON* ackMsgs;
WITH_MUTEX( &dc->ackTimer.mutex );
ackMsgs = dc->ackTimer.msgs;
dc->ackTimer.msgs = NULL;
dc->ackTimer.key = 0;
END_WITH_MUTEX();
XP_ASSERT( 0 < cJSON_GetArraySize( ackMsgs ) );
if ( fired ) {
cJSON* params = cJSON_CreateObject();
cJSON_AddItemToObject( params, "msgs", ackMsgs );
dutil_sendViaWeb( dutil, xwe, 0, "ack2", params );
cJSON_Delete( params );
} else {
XP_LOGFF( "Dropping ack messages -- but should store them!" );
cJSON_Delete( ackMsgs );
}
}
static void
setAckSendTimerLocked( XW_DUtilCtxt* dutil, XWEnv xwe, DevCtxt* dc )
{
if ( 0 == dc->ackTimer.key ) {
XP_U32 inWhenMS = 10 * 1000;
dc->ackTimer.key = tmr_set( dutil, xwe, inWhenMS, onAckSendTimer,
dutil );
XP_ASSERT( 0 != dc->ackTimer.key );
}
}
static void static void
ackMQTTMsg( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* topic, ackMQTTMsg( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* topic,
XP_U32 gameID, const XP_U8* buf, XP_U16 len ) XP_U32 gameID, const XP_U8* buf, XP_U16 len )
{ {
cJSON* params = cJSON_CreateObject(); cJSON* msg = cJSON_CreateObject();
#if 1 cJSON_AddStringToObject( msg, "topic", topic );
cJSON* msgs = cJSON_CreateArray();
/* This belongs in a loop */
{
cJSON* msg = cJSON_CreateObject();
cJSON_AddStringToObject( msg, "topic", topic );
Md5SumBuf sb;
dutil_md5sum( dutil, xwe, buf, len, &sb );
cJSON_AddStringToObject( msg, "sum", sb.buf );
cJSON_AddNumberToObject( msg, "gid", gameID );
cJSON_AddItemToArray(msgs, msg);
}
cJSON_AddItemToObject(params, "msgs", msgs );
dutil_sendViaWeb( dutil, xwe, 0, "ack2", params );
#else
cJSON_AddStringToObject( params, "topic", topic );
Md5SumBuf sb; Md5SumBuf sb;
dutil_md5sum( dutil, xwe, buf, len, &sb ); dutil_md5sum( dutil, xwe, buf, len, &sb );
cJSON_AddStringToObject( params, "sum", sb.buf ); cJSON_AddStringToObject( msg, "sum", sb.buf );
cJSON_AddNumberToObject( params, "gid", gameID ); cJSON_AddNumberToObject( msg, "gid", gameID );
dutil_sendViaWeb( dutil, xwe, 0, "ack", params ); DevCtxt* dc = load( dutil, xwe );
#endif WITH_MUTEX( &dc->ackTimer.mutex );
cJSON_Delete( params ); if ( !dc->ackTimer.msgs ) {
dc->ackTimer.msgs = cJSON_CreateArray();
}
cJSON_AddItemToArray( dc->ackTimer.msgs, msg );
setAckSendTimerLocked( dutil, xwe, dc );
END_WITH_MUTEX();
} }
void void
@ -674,14 +704,14 @@ popForKey( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U32 key )
WSData* item = NULL; WSData* item = NULL;
DevCtxt* dc = load( dutil, xwe ); DevCtxt* dc = load( dutil, xwe );
pthread_mutex_lock( &dc->webSendMutex ); WITH_MUTEX(&dc->webSendMutex);
GetByKeyData gbkd = { .resultKey = key, }; GetByKeyData gbkd = { .resultKey = key, };
dc->webSendData = (WSData*)dll_map( &dc->webSendData->links, dc->webSendData = (WSData*)dll_map( &dc->webSendData->links,
getByKeyProc, NULL, &gbkd ); getByKeyProc, NULL, &gbkd );
item = gbkd.found; item = gbkd.found;
pthread_mutex_unlock( &dc->webSendMutex ); END_WITH_MUTEX();
XP_LOGFFV( "(key: %d) => %p", key, item ); XP_LOGFFV( "(key: %d) => %p", key, item );
return item; return item;
} }
@ -690,11 +720,11 @@ static XP_U32
addWithKey( XW_DUtilCtxt* dutil, XWEnv xwe, WSData* wsdp ) addWithKey( XW_DUtilCtxt* dutil, XWEnv xwe, WSData* wsdp )
{ {
DevCtxt* dc = load( dutil, xwe ); DevCtxt* dc = load( dutil, xwe );
pthread_mutex_lock( &dc->webSendMutex ); WITH_MUTEX(&dc->webSendMutex);
wsdp->resultKey = ++dc->mWebSendKey; wsdp->resultKey = ++dc->mWebSendKey;
dc->webSendData = (WSData*) dc->webSendData = (WSData*)
dll_insert( &dc->webSendData->links, &wsdp->links, NULL ); dll_insert( &dc->webSendData->links, &wsdp->links, NULL );
pthread_mutex_unlock( &dc->webSendMutex ); END_WITH_MUTEX();
XP_LOGFFV( "(%p) => %d", wsdp, wsdp->resultKey ); XP_LOGFFV( "(%p) => %d", wsdp, wsdp->resultKey );
return wsdp->resultKey; return wsdp->resultKey;
} }
@ -752,9 +782,9 @@ dvc_onWebSendResult( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U32 resultKey,
static void static void
freeWSState( XW_DUtilCtxt* dutil, DevCtxt* dc ) freeWSState( XW_DUtilCtxt* dutil, DevCtxt* dc )
{ {
pthread_mutex_lock( &dc->webSendMutex ); WITH_MUTEX( &dc->webSendMutex );
dll_removeAll( &dc->webSendData->links, delWSDatum, dutil ); dll_removeAll( &dc->webSendData->links, delWSDatum, dutil );
pthread_mutex_unlock( &dc->webSendMutex ); END_WITH_MUTEX();
} }
typedef struct _PhoniesMapState { typedef struct _PhoniesMapState {
@ -1147,7 +1177,9 @@ dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe )
DevCtxt* dc = dutil->devCtxt = XP_CALLOC( dutil->mpool, sizeof(*dc) ); DevCtxt* dc = dutil->devCtxt = XP_CALLOC( dutil->mpool, sizeof(*dc) );
dc->webSendData = NULL; dc->webSendData = NULL;
dc->mWebSendKey = 0; dc->mWebSendKey = 0;
pthread_mutex_init( &dc->webSendMutex, NULL );
mtx_init( &dc->webSendMutex, XP_FALSE );
mtx_init( &dc->ackTimer.mutex, XP_FALSE );
loadPhoniesData( dutil, xwe, dc ); loadPhoniesData( dutil, xwe, dc );
@ -1161,10 +1193,10 @@ void
dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ) dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe )
{ {
DevCtxt* dc = freePhonyState( dutil, xwe ); DevCtxt* dc = freePhonyState( dutil, xwe );
freeWSState( dutil, dc ); freeWSState( dutil, dc );
pthread_mutex_destroy( &dc->webSendMutex ); mtx_destroy( &dc->webSendMutex );
mtx_destroy( &dc->ackTimer.mutex );
XP_FREEP( dutil->mpool, &dc ); XP_FREEP( dutil->mpool, &dc );
} }

View file

@ -300,7 +300,7 @@ pushEntry( StackCtxt* stack, const StackEntry* entry )
#ifdef DEBUG_HASHING #ifdef DEBUG_HASHING
XP_U32 origHash = stack_getHash( stack ); XP_U32 origHash = stack_getHash( stack );
StackEntry prevTop; StackEntry prevTop = {};
if ( 1 < stack->nPlayers && if ( 1 < stack->nPlayers &&
stack_getNthEntry( stack, stack->nEntries - 1, &prevTop ) ) { stack_getNthEntry( stack, stack->nEntries - 1, &prevTop ) ) {
XP_ASSERT( stack->inDuplicateMode || prevTop.playerNum != entry->playerNum ); XP_ASSERT( stack->inDuplicateMode || prevTop.playerNum != entry->playerNum );

View file

@ -33,8 +33,8 @@ typedef struct StatsState {
static const XP_UCHAR* STATtoStr(STAT stat); static const XP_UCHAR* STATtoStr(STAT stat);
static XP_U32* loadCounts( XW_DUtilCtxt* dutil, XWEnv xwe ); static XP_U32* loadCounts( XW_DUtilCtxt* dutil, XWEnv xwe );
static void storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe ); static void storeCountsLocked( XW_DUtilCtxt* dutil, XWEnv xwe );
static void setStoreTimer( XW_DUtilCtxt* dutil, XWEnv xwe ); static void setStoreTimerLocked( XW_DUtilCtxt* dutil, XWEnv xwe );
void void
sts_init( XW_DUtilCtxt* dutil ) sts_init( XW_DUtilCtxt* dutil )
@ -66,7 +66,7 @@ sts_increment( XW_DUtilCtxt* dutil, XWEnv xwe, STAT stat )
} }
++ss->statsVals[stat]; ++ss->statsVals[stat];
setStoreTimer( dutil, xwe ); setStoreTimerLocked( dutil, xwe );
END_WITH_MUTEX(); END_WITH_MUTEX();
} }
} }
@ -104,7 +104,7 @@ sts_clearAll( XW_DUtilCtxt* dutil, XWEnv xwe )
ss->statsVals ss->statsVals
= XP_CALLOC( dutil->mpool, sizeof(*ss->statsVals) * STAT_NSTATS ); = XP_CALLOC( dutil->mpool, sizeof(*ss->statsVals) * STAT_NSTATS );
storeCounts( dutil, xwe ); storeCountsLocked( dutil, xwe );
END_WITH_MUTEX(); END_WITH_MUTEX();
} }
@ -133,7 +133,7 @@ STATtoStr(STAT stat)
} }
static void static void
storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe ) storeCountsLocked( XW_DUtilCtxt* dutil, XWEnv xwe )
{ {
StatsState* ss = dutil->statsState; StatsState* ss = dutil->statsState;
XP_ASSERT( !!ss ); XP_ASSERT( !!ss );
@ -188,7 +188,7 @@ onStoreTimer( void* closure, XWEnv xwe, XP_Bool fired )
XP_ASSERT( !!ss ); XP_ASSERT( !!ss );
WITH_MUTEX( &ss->mutex ); WITH_MUTEX( &ss->mutex );
storeCounts( dutil, xwe ); storeCountsLocked( dutil, xwe );
ss->timerSet = XP_FALSE; ss->timerSet = XP_FALSE;
END_WITH_MUTEX(); END_WITH_MUTEX();
LOG_RETURN_VOID(); LOG_RETURN_VOID();
@ -196,7 +196,7 @@ onStoreTimer( void* closure, XWEnv xwe, XP_Bool fired )
#endif #endif
static void static void
setStoreTimer( XW_DUtilCtxt* dutil, XWEnv xwe ) setStoreTimerLocked( XW_DUtilCtxt* dutil, XWEnv xwe )
{ {
#ifdef DUTIL_TIMERS #ifdef DUTIL_TIMERS
StatsState* ss = dutil->statsState; StatsState* ss = dutil->statsState;

View file

@ -245,7 +245,8 @@ class Device():
# called by thread proc # called by thread proc
def _launchProc(self): def _launchProc(self):
assert not self.endTime assert not self.endTime
self.endTime = datetime.datetime.now() + datetime.timedelta(seconds = 5) self.endTime = datetime.datetime.now() + \
datetime.timedelta(seconds = self.args.MIN_APP_LIFE)
args = [ self.script, '--close-stdin', '--skip-user-errors' ] args = [ self.script, '--close-stdin', '--skip-user-errors' ]
if not self.args.USE_GTK: args.append('--curses') if not self.args.USE_GTK: args.append('--curses')
@ -913,6 +914,8 @@ def mkParser():
parser.add_argument('--timer-seconds', dest='TIMER_SECS', default=10, type=int, parser.add_argument('--timer-seconds', dest='TIMER_SECS', default=10, type=int,
help='Enable game timer with game this many seconds long') help='Enable game timer with game this many seconds long')
parser.add_argument('--min-app-life', dest='MIN_APP_LIFE', default=5, type=int,
help='Minimum number of seconds app will run after each launch')
parser.add_argument('--with-sms', dest = 'WITH_SMS', action = 'store_true') parser.add_argument('--with-sms', dest = 'WITH_SMS', action = 'store_true')
parser.add_argument('--without-sms', dest = 'WITH_SMS', default = False, action = 'store_false') parser.add_argument('--without-sms', dest = 'WITH_SMS', default = False, action = 'store_false')