From f406757fb2619153a504c733e08a16e418f4b2b3 Mon Sep 17 00:00:00 2001 From: Eric House Date: Mon, 12 Aug 2024 21:04:46 -0700 Subject: [PATCH] add generic timers (with dutil component for scheduling) --- xwords4/common/config.mk | 1 + xwords4/common/device.c | 10 +++ xwords4/common/device.h | 4 + xwords4/common/dutil.c | 3 + xwords4/common/dutil.h | 16 ++-- xwords4/common/mempool.c | 10 ++- xwords4/common/stats.c | 59 ++++++++++---- xwords4/common/timers.c | 166 +++++++++++++++++++++++++++++++++++++++ xwords4/common/timers.h | 40 ++++++++++ xwords4/common/xwmutex.c | 10 +++ xwords4/common/xwmutex.h | 9 +++ xwords4/linux/lindutil.c | 51 ++++++------ xwords4/linux/mqttcon.c | 3 +- 13 files changed, 324 insertions(+), 58 deletions(-) create mode 100644 xwords4/common/timers.c create mode 100644 xwords4/common/timers.h diff --git a/xwords4/common/config.mk b/xwords4/common/config.mk index f8c7695ad..ab2751157 100644 --- a/xwords4/common/config.mk +++ b/xwords4/common/config.mk @@ -99,6 +99,7 @@ COMMON5 = \ $(COMMONOBJDIR)/knownplyr.o \ $(COMMONOBJDIR)/dllist.o \ $(COMMONOBJDIR)/stats.o \ + $(COMMONOBJDIR)/timers.o \ $(COMMONOBJDIR)/md5.o \ CJSON = \ diff --git a/xwords4/common/device.c b/xwords4/common/device.c index c9f79e218..f5cdd1fa7 100644 --- a/xwords4/common/device.c +++ b/xwords4/common/device.c @@ -28,6 +28,7 @@ #include "strutils.h" #include "nli.h" #include "dbgutil.h" +#include "timers.h" #ifdef DEBUG # define MAGIC_INITED 0x8283413F @@ -1036,6 +1037,15 @@ dvc_getPhoniesFor( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* code, dll_map( &pdc->head->links, getWordsProc, NULL, &gws ); } +#ifdef DUTIL_TIMERS +void +dvc_onTimerFired( XW_DUtilCtxt* dutil, XWEnv xwe, TimerKey key ) +{ + XP_LOGFF( "(key: %d)", key ); + tmr_fired( dutil, xwe, key ); +} +#endif + static ForEachAct findPhonyProc2( const DLHead* elem, void* closure ) { diff --git a/xwords4/common/device.h b/xwords4/common/device.h index f9f8a0bce..3b82b9133 100644 --- a/xwords4/common/device.h +++ b/xwords4/common/device.h @@ -77,6 +77,10 @@ void dvc_getIsoCodes( XW_DUtilCtxt* dutil, XWEnv env, WordCollector proc, void dvc_getPhoniesFor( XW_DUtilCtxt* dutil, XWEnv env, const XP_UCHAR* code, WordCollector proc, void* closure ); +#ifdef DUTIL_TIMERS +void dvc_onTimerFired( XW_DUtilCtxt* dutil, XWEnv env, TimerKey key ); +#endif + /* All platforms need to call this shortly after setting up their XW_DUtilCtxt */ void dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe ); void dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ); diff --git a/xwords4/common/dutil.c b/xwords4/common/dutil.c index e8b95105f..0ba7ede9b 100644 --- a/xwords4/common/dutil.c +++ b/xwords4/common/dutil.c @@ -26,6 +26,7 @@ #include "knownplyr.h" #include "device.h" #include "stats.h" +#include "timers.h" static void super_dutil_storeStream( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* keys[], @@ -66,12 +67,14 @@ dutil_super_init( MPFORMAL XW_DUtilCtxt* dutil ) SET_VTABLE_ENTRY( &dutil->vtable, dutil_loadStream, super ); SET_VTABLE_ENTRY( &dutil->vtable, dutil_storeStream, super ); + tmr_init( dutil ); sts_init( dutil ); } void dutil_super_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ) { + tmr_cleanup( dutil, xwe ); kplr_cleanup( dutil ); sts_cleanup( dutil, xwe ); dvc_cleanup( dutil, xwe ); diff --git a/xwords4/common/dutil.h b/xwords4/common/dutil.h index d750a6ccf..a9dad67ac 100644 --- a/xwords4/common/dutil.h +++ b/xwords4/common/dutil.h @@ -44,7 +44,7 @@ typedef struct _Md5SumBuf { #define KEY_WILDCARD "*" #ifdef DUTIL_TIMERS -typedef void (*DUtilTimerProc)( XWEnv xwe, void* closure, size_t closureSize ); +typedef XP_U32 TimerKey; #endif typedef struct _DUtilVtable { XP_U32 (*m_dutil_getCurSeconds)( XW_DUtilCtxt* duc, XWEnv xwe ); @@ -84,9 +84,8 @@ typedef struct _DUtilVtable { #endif #ifdef DUTIL_TIMERS - void (*m_dutil_setTimer)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 when, DUtilTimerProc proc, - void* closure, size_t closureSize ); - void (*m_dutil_clearTimer)( XW_DUtilCtxt* duc, XWEnv xwe, DUtilTimerProc proc ); + void (*m_dutil_setTimer)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 when, TimerKey key ); + void (*m_dutil_clearTimer)( XW_DUtilCtxt* duc, XWEnv xwe, TimerKey key ); #endif void (*m_dutil_md5sum)( XW_DUtilCtxt* duc, XWEnv xwe, const XP_U8* ptr, XP_U32 len, Md5SumBuf* sb ); @@ -118,6 +117,7 @@ struct XW_DUtilCtxt { void* closure; void* devCtxt; /* owned by device.c */ void* statsState; /* owned by stats.c */ + void* timersState; /* owned by timers.c */ #ifdef XWFEATURE_KNOWNPLAYERS /* owned by knownplyr.c */ void* kpCtxt; pthread_mutex_t kpMutex; @@ -168,10 +168,10 @@ void dutil_super_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ); #endif #ifdef DUTIL_TIMERS -# define dutil_setTimer( duc, xwe, when, proc, closure, siz ) \ - (duc)->vtable.m_dutil_setTimer((duc), (xwe), (when), (proc), (closure), (siz)) -# define dutil_clearTimer( duc, xwe, proc ) \ - (duc)->vtable.m_dutil_clearTimer((duc), (xwe), (proc) ) +# define dutil_setTimer( duc, xwe, when, key ) \ + (duc)->vtable.m_dutil_setTimer((duc), (xwe), (when), (key)) +# define dutil_clearTimer( duc, xwe, key ) \ + (duc)->vtable.m_dutil_clearTimer((duc), (xwe), (key) ) #endif # define dutil_md5sum( duc, e, p, l, b ) \ diff --git a/xwords4/common/mempool.c b/xwords4/common/mempool.c index 34e650c0e..a3c85afcd 100644 --- a/xwords4/common/mempool.c +++ b/xwords4/common/mempool.c @@ -306,14 +306,16 @@ mpool_free( MemPoolCtx* mpool, void* ptr, const char* file, MemPoolEntry* entry = findEntryFor( mpool, ptr, &prev ); if ( !entry ) { - XP_LOGFF( "findEntryFor failed; pool %p, line %d in %s", mpool, lineNo, file ); + XP_LOGFF( "findEntryFor failed; pool %p, line %d in %s", mpool, + lineNo, file ); XP_ASSERT( 0 ); } else { #ifdef MPOOL_DEBUG - XP_LOGFF( "(ptr=%p):size=%d,index=%d,func=%s,file=%s,lineNo=%d); called from %s", - entry->ptr, entry->size, entry->index, entry->func, entry->fileName, - entry->lineNo, func ); + XP_LOGFF( "(ptr=%p):size=%d,index=%d,func=%s,file=%s,lineNo=%d); " + "called from %s", + entry->ptr, entry->size, entry->index, entry->func, + entry->fileName, entry->lineNo, func ); #else XP_USE(func); /* shut up, compiler */ #endif diff --git a/xwords4/common/stats.c b/xwords4/common/stats.c index b8ab47e58..8004e2406 100644 --- a/xwords4/common/stats.c +++ b/xwords4/common/stats.c @@ -22,15 +22,19 @@ #include "device.h" #include "xwstream.h" #include "strutils.h" +#include "dbgutil.h" +#include "timers.h" typedef struct StatsState { XP_U32* statsVals; MutexState mutex; + XP_Bool timerSet; } StatsState; static const XP_UCHAR* STATtoStr(STAT stat); static XP_U32* loadCounts( XW_DUtilCtxt* dutil, XWEnv xwe ); static void storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe ); +static void setStoreTimer( XW_DUtilCtxt* dutil, XWEnv xwe ); void sts_init( XW_DUtilCtxt* dutil ) @@ -41,10 +45,9 @@ sts_init( XW_DUtilCtxt* dutil ) } void -sts_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ) +sts_cleanup( XW_DUtilCtxt* dutil, XWEnv XP_UNUSED(xwe) ) { StatsState* ss = dutil->statsState; - storeCounts( dutil, xwe ); XP_ASSERT( !!ss ); XP_FREEP( dutil->mpool, &ss->statsVals ); XP_FREEP( dutil->mpool, &ss ); @@ -62,8 +65,7 @@ sts_increment( XW_DUtilCtxt* dutil, XWEnv xwe, STAT stat ) } ++ss->statsVals[stat]; - XP_LOGFF( "bad: storing after every change" ); - storeCounts( dutil, xwe ); + setStoreTimer( dutil, xwe ); END_WITH_MUTEX(); } } @@ -83,20 +85,13 @@ sts_export( XW_DUtilCtxt* dutil, XWEnv xwe ) XP_U32 val = ss->statsVals[ii]; if ( 0 != val ) { const XP_UCHAR* nam = STATtoStr(ii); - cJSON_AddNumberToObject(result, nam, val); + cJSON_AddNumberToObject( result, nam, val ); } } END_WITH_MUTEX(); return result; } -/* void */ -/* sts_increment( XW_DUtilCtxt* dutil, XWEnv XP_UNUSED(xwe), STS_KEY key ) */ -/* { */ -/* StatsState* ss = dutil->statsState; */ -/* ++ss->stats[key]; */ -/* } */ - void sts_clearAll( XW_DUtilCtxt* dutil, XWEnv xwe ) { @@ -108,9 +103,8 @@ sts_clearAll( XW_DUtilCtxt* dutil, XWEnv xwe ) ss->statsVals = XP_CALLOC( dutil->mpool, sizeof(*ss->statsVals) * STAT_NSTATS ); - END_WITH_MUTEX(); - storeCounts( dutil, xwe ); + END_WITH_MUTEX(); } static const XP_UCHAR* @@ -146,7 +140,6 @@ storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe ) XWStreamCtxt* stream = mkStream( dutil ); stream_putU8( stream, 0 ); /* version */ - WITH_MUTEX( &ss->mutex ); if ( !!ss->statsVals ) { for ( int ii = 0; ii < STAT_NSTATS; ++ii ) { XP_U32 val = ss->statsVals[ii]; @@ -156,7 +149,6 @@ storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe ) } } } - END_WITH_MUTEX(); const XP_UCHAR* keys[] = { STATS_KEY, NULL }; dutil_storeStream( dutil, xwe, keys, stream ); @@ -184,3 +176,38 @@ loadCounts( XW_DUtilCtxt* dutil, XWEnv xwe ) stream_destroy( stream ); return statsVals; } + +#ifdef DUTIL_TIMERS +static void +onStoreTimer( void* closure, XWEnv xwe, XP_Bool fired ) +{ + XP_LOGFF( "(fired: %s)", boolToStr(fired) ); + XW_DUtilCtxt* dutil = (XW_DUtilCtxt*)closure; + StatsState* ss = dutil->statsState; + XP_ASSERT( !!ss ); + + WITH_MUTEX( &ss->mutex ); + storeCounts( dutil, xwe ); + ss->timerSet = XP_FALSE; + END_WITH_MUTEX(); + LOG_RETURN_VOID(); +} +#endif + +static void +setStoreTimer( XW_DUtilCtxt* dutil, XWEnv xwe ) +{ +#ifdef DUTIL_TIMERS + StatsState* ss = dutil->statsState; + XP_ASSERT( !!ss ); + if ( !ss->timerSet ) { + ss->timerSet = XP_TRUE; + XP_U32 inWhenMS = 5 * 1000; + TimerKey key = tmr_set( dutil, xwe, inWhenMS, onStoreTimer, dutil ); + XP_LOGFF( "tmr_set() => %d", key ); + } +#else + XP_USE(dutil); + XP_USE(xwe); +#endif +} diff --git a/xwords4/common/timers.c b/xwords4/common/timers.c new file mode 100644 index 000000000..da72c68e8 --- /dev/null +++ b/xwords4/common/timers.c @@ -0,0 +1,166 @@ +/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ +/* + * Copyright 2024 by Eric House (xwords@eehouse.org). All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "timers.h" +#include "xwmutex.h" +#include "dllist.h" + +#ifdef DUTIL_TIMERS +typedef struct _TimerState { + DLHead links; + TimerProc proc; + void* closure; + TimerKey key; + XP_U32 inWhen; +} TimerState; + +typedef struct _TimerMgrState { + XW_DUtilCtxt* dutil; + MutexState mutex; + XP_U32 nextKey; + TimerState* timers; +} TimerMgrState; + +static void clearPendings( XW_DUtilCtxt* dutil, XWEnv xwe ); + +void +tmr_init( XW_DUtilCtxt* dutil ) +{ + LOG_FUNC(); + XP_ASSERT( !dutil->timersState ); + TimerMgrState* tms = XP_CALLOC( dutil->mpool, sizeof(*tms) ); + tms->dutil = dutil; + dutil->timersState = tms; + initMutex( &tms->mutex, XP_TRUE ); +} + +void +tmr_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ) +{ + TimerMgrState* timersState = (TimerMgrState*)dutil->timersState; + XP_ASSERT( !!timersState ); + clearPendings( dutil, xwe ); + XP_FREEP( dutil->mpool, &dutil->timersState ); +} + +TimerKey +tmr_set( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U32 inWhen, + TimerProc proc, void* closure ) +{ + TimerKey key; + TimerMgrState* timersState = (TimerMgrState*)dutil->timersState; + XP_ASSERT( !!timersState ); + + TimerState* ts = XP_CALLOC( dutil->mpool, sizeof(*ts) ); + XP_LOGFF( "allocated timer %p", ts ); + ts->proc = proc; + ts->closure = closure; + ts->inWhen = inWhen; + + WITH_MUTEX( &timersState->mutex ); + key = ts->key = ++timersState->nextKey; + timersState->timers = (TimerState*) + dll_insert( &timersState->timers->links, &ts->links, NULL ); + END_WITH_MUTEX(); + + dutil_setTimer( dutil, xwe, inWhen, ts->key ); + return key; +} + +static void +timerFired( XW_DUtilCtxt* dutil, XWEnv xwe, TimerState* timer, XP_Bool fired ) +{ + XP_LOGFF( "(timer=%p); key=%d", timer, timer->key ); + (*timer->proc)( timer->closure, xwe, fired ); + XP_FREE( dutil->mpool, timer ); +} + +typedef struct _FindByKeyState { + TimerKey key; + TimerState* found; +} FindByKeyState; + +static ForEachAct +findByKeyProc( const DLHead* elem, void* closure ) +{ + ForEachAct result = FEA_OK; + FindByKeyState* fbksp = (FindByKeyState*)closure; + TimerState* ts = (TimerState*)elem; + if ( ts->key == fbksp->key ) { + fbksp->found = ts; + result = FEA_REMOVE | FEA_EXIT; + } + return result; +} + +void +tmr_fired( XW_DUtilCtxt* dutil, XWEnv xwe, TimerKey key ) +{ + XP_LOGFF( "(key=%d)", key ); + TimerMgrState* timersState = (TimerMgrState*)dutil->timersState; + XP_ASSERT( !!timersState ); + + FindByKeyState fbks = { .key = key }; + + WITH_MUTEX( &timersState->mutex ); + timersState->timers = (TimerState*) + dll_map( &timersState->timers->links, findByKeyProc, NULL, &fbks ); + END_WITH_MUTEX(); + + if ( !!fbks.found ) { + timerFired( dutil, xwe, fbks.found, XP_TRUE ); + } else { + XP_LOGFF( "no timer found for key %d", key ); + } +} + +typedef struct _FireAndDisposeState { + XW_DUtilCtxt* dutil; + XWEnv xwe; +} FireAndDisposeState; + +static void +fireAndDispose( DLHead* elem, void* closure ) +{ + TimerState* ts = (TimerState*)elem; + FireAndDisposeState* fadsp = (FireAndDisposeState*)closure; + dutil_clearTimer( fadsp->dutil, fadsp->xwe, ts->key ); + timerFired( fadsp->dutil, fadsp->xwe, ts, XP_FALSE ); /* disposes ts */ +} + +static void +clearPendings( XW_DUtilCtxt* dutil, XWEnv xwe ) +{ + TimerMgrState* timersState = (TimerMgrState*)dutil->timersState; + TimerState* timers; + + /* Grab the list so we can run over it without a mutex */ + WITH_MUTEX( &timersState->mutex ); + timers = timersState->timers; + timersState->timers = NULL; + END_WITH_MUTEX(); + + FireAndDisposeState fads = { + .xwe = xwe, + .dutil = dutil, + }; + dll_removeAll( &timers->links, fireAndDispose, &fads ); +} + +#endif diff --git a/xwords4/common/timers.h b/xwords4/common/timers.h new file mode 100644 index 000000000..8b9b8a2dc --- /dev/null +++ b/xwords4/common/timers.h @@ -0,0 +1,40 @@ +/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ +/* + * Copyright 2024 by Eric House (xwords@eehouse.org). All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TIMERS_H_ +#define _TIMERS_H_ + +# ifdef DUTIL_TIMERS + +# include "dutil.h" + +void tmr_init( XW_DUtilCtxt* dutil ); +void tmr_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ); + +/* Pass false for fired if we're clearing unfired timers, e.g. on shutdown */ +typedef void (*TimerProc)(void* closure, XWEnv xwe, XP_Bool fired); +TimerKey tmr_set( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U32 inWhenMS, + TimerProc proc, void* closure ); +void tmr_fired( XW_DUtilCtxt* dutil, XWEnv xwe, TimerKey key ); + +# else +# define tmr_init( dutil ) +# define tmr_cleanup( dutil, xwe ) +# endif +#endif diff --git a/xwords4/common/xwmutex.c b/xwords4/common/xwmutex.c index e1c95120b..e756300d4 100644 --- a/xwords4/common/xwmutex.c +++ b/xwords4/common/xwmutex.c @@ -33,4 +33,14 @@ initMutex( MutexState* mutex, XP_Bool recursive ) pthread_mutex_init( &mutex->mutex, &attr ); ret = pthread_mutexattr_destroy(&attr); XP_ASSERT(0 == ret); + +#ifdef DEBUG + /* if ( recursive ) { */ + /* XP_LOGFF( "testing recursive call..." ); */ + /* WITH_MUTEX( mutex ); */ + /* WITH_MUTEX( mutex ); */ + /* END_WITH_MUTEX(); */ + /* END_WITH_MUTEX(); */ + /* } */ +#endif } diff --git a/xwords4/common/xwmutex.h b/xwords4/common/xwmutex.h index fcb6802f9..258eac8c6 100644 --- a/xwords4/common/xwmutex.h +++ b/xwords4/common/xwmutex.h @@ -28,10 +28,18 @@ typedef struct _MutexState { pthread_mutex_t mutex; } MutexState; +#if 0 +# define MUTEX_LOG(...) XP_LOGFF(__VA_ARGS__) +#else +# define MUTEX_LOG(...) +#endif + #define WITH_MUTEX_LOCK_DEBUG(STATEP) { \ MutexState* _state = (STATEP); \ time_t startTime = time(NULL); \ + MUTEX_LOG( "blocking for mutex %p", _state ); \ pthread_mutex_lock(&_state->mutex); \ + MUTEX_LOG( "got mutex %p", _state ); \ time_t gotItTime = time(NULL); \ time_t _elapsed = gotItTime-startTime; \ if ( 0 < _elapsed ) { \ @@ -45,6 +53,7 @@ typedef struct _MutexState { XP_LOGFF("held mutex for %lds", _elapsed); \ } \ pthread_mutex_unlock(&_state->mutex); \ + MUTEX_LOG( "released mutex %p", _state ); \ } \ #define WITH_MUTEX_LOCK_RELEASE(COMMS) { \ diff --git a/xwords4/linux/lindutil.c b/xwords4/linux/lindutil.c index 21454c490..c0e51458a 100644 --- a/xwords4/linux/lindutil.c +++ b/xwords4/linux/lindutil.c @@ -315,11 +315,11 @@ linux_dutil_getRegValues( XW_DUtilCtxt* duc, XWEnv xwe ) return results; } +#ifdef DUTIL_TIMERS + typedef struct _TimerClosure { XW_DUtilCtxt* duc; - DUtilTimerProc proc; - void* closure; - size_t closureSize; + TimerKey key; guint src; } TimerClosure; @@ -327,35 +327,23 @@ static gint timer_proc( gpointer data ) { TimerClosure* tc = (TimerClosure*)data; - XP_LOGFF( "calling timer proc" ); - (*tc->proc)( NULL_XWE, tc->closure, tc->closureSize ); - XP_LOGFF( "timer proc done" ); - XP_FREEP( tc->duc->mpool, &tc->closure ); - - LinDUtilCtxt* lduc = (LinDUtilCtxt*)tc->duc; - GSList** timers = &lduc->timers; - *timers = g_slist_remove( *timers, tc ); - - XP_LOGFF( "after firing, length %d", g_slist_length(*timers) ); - - XP_FREEP( tc->duc->mpool, &tc ); - return 0; + XP_LOGFF( "calling dvc_onTimerFired()" ); + dvc_onTimerFired( tc->duc, NULL_XWE, tc->key ); + g_free( tc ); + return G_SOURCE_REMOVE; } -#ifdef DUTIL_TIMERS static void -linux_dutil_setTimer( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 when, - DUtilTimerProc proc, void* closure, size_t closureSize ) +linux_dutil_setTimer( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 inWhenMS, TimerKey key ) { XP_USE(xwe); /* I assume I'll need this on the Android side */ - TimerClosure* tc = XP_MALLOC(duc->mpool, sizeof(*tc)); + TimerClosure* tc = g_malloc(sizeof(*tc)); tc->duc = duc; - tc->closureSize = closureSize; - tc->closure = XP_MALLOC( duc->mpool, closureSize ); - XP_MEMCPY( tc->closure, closure, closureSize ); - tc->proc = proc; - tc->src = g_timeout_add( when, timer_proc, tc ); + tc->key = key; + + XP_LOGFF( "key: %d, inWhenMS: %d", key, inWhenMS ); + tc->src = g_timeout_add( inWhenMS, timer_proc, tc ); LinDUtilCtxt* lduc = (LinDUtilCtxt*)duc; GSList** timers = &lduc->timers; @@ -365,14 +353,15 @@ linux_dutil_setTimer( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 when, } static gint -findByProc( gconstpointer elemData, gconstpointer proc ) +findByProc( gconstpointer elemData, gconstpointer keyp ) { TimerClosure* tc = (TimerClosure*)elemData; - return tc->proc == proc ? 0 : 1; + TimerKey* key = (TimerKey*)keyp; + return tc->key == *key ? 0 : 1; /* return 0 on success */ } static void -linux_dutil_clearTimer( XW_DUtilCtxt* duc, XWEnv xwe, DUtilTimerProc proc ) +linux_dutil_clearTimer( XW_DUtilCtxt* duc, XWEnv xwe, TimerKey key ) { /* Will probably want to store the TimerClosure instances above in a list that can be searched here for its proc value, then its src field used @@ -384,11 +373,15 @@ linux_dutil_clearTimer( XW_DUtilCtxt* duc, XWEnv xwe, DUtilTimerProc proc ) LinDUtilCtxt* lduc = (LinDUtilCtxt*)duc; GSList** timers = &lduc->timers; while ( !!*timers ) { - GSList* elem = g_slist_find_custom( *timers, proc, findByProc ); + GSList* elem = g_slist_find_custom( *timers, &key, findByProc ); if ( !elem ) { break; } + TimerClosure* tc = (TimerClosure*)elem->data; *timers = g_slist_remove( *timers, elem ); + + g_source_remove( tc->src ); + g_free( tc ); ++count; } XP_LOGFF( "removed %d timers", count ); diff --git a/xwords4/linux/mqttcon.c b/xwords4/linux/mqttcon.c index e3ac8a076..162f1b3a1 100644 --- a/xwords4/linux/mqttcon.c +++ b/xwords4/linux/mqttcon.c @@ -399,7 +399,8 @@ mqttc_cleanup( LaunchParams* params ) storage->mosq = NULL; mosquitto_lib_cleanup(); - XP_LOGFF( "quitting with %d undelievered messages", g_slist_length(storage->queue) ); + XP_LOGFF( "quitting with %d undelivered messages", + g_slist_length(storage->queue) ); XP_ASSERT( params->mqttConStorage == storage ); /* cheat */ XP_FREEP( params->mpool, &storage );