add generic timers (with dutil component for scheduling)

This commit is contained in:
Eric House 2024-08-12 21:04:46 -07:00
parent ad651c6cba
commit f406757fb2
13 changed files with 324 additions and 58 deletions

View file

@ -99,6 +99,7 @@ COMMON5 = \
$(COMMONOBJDIR)/knownplyr.o \ $(COMMONOBJDIR)/knownplyr.o \
$(COMMONOBJDIR)/dllist.o \ $(COMMONOBJDIR)/dllist.o \
$(COMMONOBJDIR)/stats.o \ $(COMMONOBJDIR)/stats.o \
$(COMMONOBJDIR)/timers.o \
$(COMMONOBJDIR)/md5.o \ $(COMMONOBJDIR)/md5.o \
CJSON = \ CJSON = \

View file

@ -28,6 +28,7 @@
#include "strutils.h" #include "strutils.h"
#include "nli.h" #include "nli.h"
#include "dbgutil.h" #include "dbgutil.h"
#include "timers.h"
#ifdef DEBUG #ifdef DEBUG
# define MAGIC_INITED 0x8283413F # 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 ); 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 static ForEachAct
findPhonyProc2( const DLHead* elem, void* closure ) findPhonyProc2( const DLHead* elem, void* closure )
{ {

View file

@ -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, void dvc_getPhoniesFor( XW_DUtilCtxt* dutil, XWEnv env, const XP_UCHAR* code,
WordCollector proc, void* closure ); 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 */ /* All platforms need to call this shortly after setting up their XW_DUtilCtxt */
void dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe ); void dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe );
void dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ); void dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe );

View file

@ -26,6 +26,7 @@
#include "knownplyr.h" #include "knownplyr.h"
#include "device.h" #include "device.h"
#include "stats.h" #include "stats.h"
#include "timers.h"
static void static void
super_dutil_storeStream( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* keys[], 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_loadStream, super );
SET_VTABLE_ENTRY( &dutil->vtable, dutil_storeStream, super ); SET_VTABLE_ENTRY( &dutil->vtable, dutil_storeStream, super );
tmr_init( dutil );
sts_init( dutil ); sts_init( dutil );
} }
void void
dutil_super_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ) dutil_super_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe )
{ {
tmr_cleanup( dutil, xwe );
kplr_cleanup( dutil ); kplr_cleanup( dutil );
sts_cleanup( dutil, xwe ); sts_cleanup( dutil, xwe );
dvc_cleanup( dutil, xwe ); dvc_cleanup( dutil, xwe );

View file

@ -44,7 +44,7 @@ typedef struct _Md5SumBuf {
#define KEY_WILDCARD "*" #define KEY_WILDCARD "*"
#ifdef DUTIL_TIMERS #ifdef DUTIL_TIMERS
typedef void (*DUtilTimerProc)( XWEnv xwe, void* closure, size_t closureSize ); typedef XP_U32 TimerKey;
#endif #endif
typedef struct _DUtilVtable { typedef struct _DUtilVtable {
XP_U32 (*m_dutil_getCurSeconds)( XW_DUtilCtxt* duc, XWEnv xwe ); XP_U32 (*m_dutil_getCurSeconds)( XW_DUtilCtxt* duc, XWEnv xwe );
@ -84,9 +84,8 @@ typedef struct _DUtilVtable {
#endif #endif
#ifdef DUTIL_TIMERS #ifdef DUTIL_TIMERS
void (*m_dutil_setTimer)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 when, DUtilTimerProc proc, void (*m_dutil_setTimer)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 when, TimerKey key );
void* closure, size_t closureSize ); void (*m_dutil_clearTimer)( XW_DUtilCtxt* duc, XWEnv xwe, TimerKey key );
void (*m_dutil_clearTimer)( XW_DUtilCtxt* duc, XWEnv xwe, DUtilTimerProc proc );
#endif #endif
void (*m_dutil_md5sum)( XW_DUtilCtxt* duc, XWEnv xwe, const XP_U8* ptr, void (*m_dutil_md5sum)( XW_DUtilCtxt* duc, XWEnv xwe, const XP_U8* ptr,
XP_U32 len, Md5SumBuf* sb ); XP_U32 len, Md5SumBuf* sb );
@ -118,6 +117,7 @@ struct XW_DUtilCtxt {
void* closure; void* closure;
void* devCtxt; /* owned by device.c */ void* devCtxt; /* owned by device.c */
void* statsState; /* owned by stats.c */ void* statsState; /* owned by stats.c */
void* timersState; /* owned by timers.c */
#ifdef XWFEATURE_KNOWNPLAYERS /* owned by knownplyr.c */ #ifdef XWFEATURE_KNOWNPLAYERS /* owned by knownplyr.c */
void* kpCtxt; void* kpCtxt;
pthread_mutex_t kpMutex; pthread_mutex_t kpMutex;
@ -168,10 +168,10 @@ void dutil_super_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe );
#endif #endif
#ifdef DUTIL_TIMERS #ifdef DUTIL_TIMERS
# define dutil_setTimer( duc, xwe, when, proc, closure, siz ) \ # define dutil_setTimer( duc, xwe, when, key ) \
(duc)->vtable.m_dutil_setTimer((duc), (xwe), (when), (proc), (closure), (siz)) (duc)->vtable.m_dutil_setTimer((duc), (xwe), (when), (key))
# define dutil_clearTimer( duc, xwe, proc ) \ # define dutil_clearTimer( duc, xwe, key ) \
(duc)->vtable.m_dutil_clearTimer((duc), (xwe), (proc) ) (duc)->vtable.m_dutil_clearTimer((duc), (xwe), (key) )
#endif #endif
# define dutil_md5sum( duc, e, p, l, b ) \ # define dutil_md5sum( duc, e, p, l, b ) \

View file

@ -306,14 +306,16 @@ mpool_free( MemPoolCtx* mpool, void* ptr, const char* file,
MemPoolEntry* entry = findEntryFor( mpool, ptr, &prev ); MemPoolEntry* entry = findEntryFor( mpool, ptr, &prev );
if ( !entry ) { 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 ); XP_ASSERT( 0 );
} else { } else {
#ifdef MPOOL_DEBUG #ifdef MPOOL_DEBUG
XP_LOGFF( "(ptr=%p):size=%d,index=%d,func=%s,file=%s,lineNo=%d); called from %s", XP_LOGFF( "(ptr=%p):size=%d,index=%d,func=%s,file=%s,lineNo=%d); "
entry->ptr, entry->size, entry->index, entry->func, entry->fileName, "called from %s",
entry->lineNo, func ); entry->ptr, entry->size, entry->index, entry->func,
entry->fileName, entry->lineNo, func );
#else #else
XP_USE(func); /* shut up, compiler */ XP_USE(func); /* shut up, compiler */
#endif #endif

View file

@ -22,15 +22,19 @@
#include "device.h" #include "device.h"
#include "xwstream.h" #include "xwstream.h"
#include "strutils.h" #include "strutils.h"
#include "dbgutil.h"
#include "timers.h"
typedef struct StatsState { typedef struct StatsState {
XP_U32* statsVals; XP_U32* statsVals;
MutexState mutex; MutexState mutex;
XP_Bool timerSet;
} StatsState; } 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 storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe );
static void setStoreTimer( XW_DUtilCtxt* dutil, XWEnv xwe );
void void
sts_init( XW_DUtilCtxt* dutil ) sts_init( XW_DUtilCtxt* dutil )
@ -41,10 +45,9 @@ sts_init( XW_DUtilCtxt* dutil )
} }
void void
sts_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe ) sts_cleanup( XW_DUtilCtxt* dutil, XWEnv XP_UNUSED(xwe) )
{ {
StatsState* ss = dutil->statsState; StatsState* ss = dutil->statsState;
storeCounts( dutil, xwe );
XP_ASSERT( !!ss ); XP_ASSERT( !!ss );
XP_FREEP( dutil->mpool, &ss->statsVals ); XP_FREEP( dutil->mpool, &ss->statsVals );
XP_FREEP( dutil->mpool, &ss ); XP_FREEP( dutil->mpool, &ss );
@ -62,8 +65,7 @@ sts_increment( XW_DUtilCtxt* dutil, XWEnv xwe, STAT stat )
} }
++ss->statsVals[stat]; ++ss->statsVals[stat];
XP_LOGFF( "bad: storing after every change" ); setStoreTimer( dutil, xwe );
storeCounts( dutil, xwe );
END_WITH_MUTEX(); END_WITH_MUTEX();
} }
} }
@ -83,20 +85,13 @@ sts_export( XW_DUtilCtxt* dutil, XWEnv xwe )
XP_U32 val = ss->statsVals[ii]; XP_U32 val = ss->statsVals[ii];
if ( 0 != val ) { if ( 0 != val ) {
const XP_UCHAR* nam = STATtoStr(ii); const XP_UCHAR* nam = STATtoStr(ii);
cJSON_AddNumberToObject(result, nam, val); cJSON_AddNumberToObject( result, nam, val );
} }
} }
END_WITH_MUTEX(); END_WITH_MUTEX();
return result; return result;
} }
/* void */
/* sts_increment( XW_DUtilCtxt* dutil, XWEnv XP_UNUSED(xwe), STS_KEY key ) */
/* { */
/* StatsState* ss = dutil->statsState; */
/* ++ss->stats[key]; */
/* } */
void void
sts_clearAll( XW_DUtilCtxt* dutil, XWEnv xwe ) sts_clearAll( XW_DUtilCtxt* dutil, XWEnv xwe )
{ {
@ -108,9 +103,8 @@ 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 );
END_WITH_MUTEX();
storeCounts( dutil, xwe ); storeCounts( dutil, xwe );
END_WITH_MUTEX();
} }
static const XP_UCHAR* static const XP_UCHAR*
@ -146,7 +140,6 @@ storeCounts( XW_DUtilCtxt* dutil, XWEnv xwe )
XWStreamCtxt* stream = mkStream( dutil ); XWStreamCtxt* stream = mkStream( dutil );
stream_putU8( stream, 0 ); /* version */ stream_putU8( stream, 0 ); /* version */
WITH_MUTEX( &ss->mutex );
if ( !!ss->statsVals ) { if ( !!ss->statsVals ) {
for ( int ii = 0; ii < STAT_NSTATS; ++ii ) { for ( int ii = 0; ii < STAT_NSTATS; ++ii ) {
XP_U32 val = ss->statsVals[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 }; const XP_UCHAR* keys[] = { STATS_KEY, NULL };
dutil_storeStream( dutil, xwe, keys, stream ); dutil_storeStream( dutil, xwe, keys, stream );
@ -184,3 +176,38 @@ loadCounts( XW_DUtilCtxt* dutil, XWEnv xwe )
stream_destroy( stream ); stream_destroy( stream );
return statsVals; 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
}

166
xwords4/common/timers.c Normal file
View file

@ -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

40
xwords4/common/timers.h Normal file
View file

@ -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

View file

@ -33,4 +33,14 @@ initMutex( MutexState* mutex, XP_Bool recursive )
pthread_mutex_init( &mutex->mutex, &attr ); pthread_mutex_init( &mutex->mutex, &attr );
ret = pthread_mutexattr_destroy(&attr); ret = pthread_mutexattr_destroy(&attr);
XP_ASSERT(0 == ret); 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
} }

View file

@ -28,10 +28,18 @@ typedef struct _MutexState {
pthread_mutex_t mutex; pthread_mutex_t mutex;
} MutexState; } MutexState;
#if 0
# define MUTEX_LOG(...) XP_LOGFF(__VA_ARGS__)
#else
# define MUTEX_LOG(...)
#endif
#define WITH_MUTEX_LOCK_DEBUG(STATEP) { \ #define WITH_MUTEX_LOCK_DEBUG(STATEP) { \
MutexState* _state = (STATEP); \ MutexState* _state = (STATEP); \
time_t startTime = time(NULL); \ time_t startTime = time(NULL); \
MUTEX_LOG( "blocking for mutex %p", _state ); \
pthread_mutex_lock(&_state->mutex); \ pthread_mutex_lock(&_state->mutex); \
MUTEX_LOG( "got mutex %p", _state ); \
time_t gotItTime = time(NULL); \ time_t gotItTime = time(NULL); \
time_t _elapsed = gotItTime-startTime; \ time_t _elapsed = gotItTime-startTime; \
if ( 0 < _elapsed ) { \ if ( 0 < _elapsed ) { \
@ -45,6 +53,7 @@ typedef struct _MutexState {
XP_LOGFF("held mutex for %lds", _elapsed); \ XP_LOGFF("held mutex for %lds", _elapsed); \
} \ } \
pthread_mutex_unlock(&_state->mutex); \ pthread_mutex_unlock(&_state->mutex); \
MUTEX_LOG( "released mutex %p", _state ); \
} \ } \
#define WITH_MUTEX_LOCK_RELEASE(COMMS) { \ #define WITH_MUTEX_LOCK_RELEASE(COMMS) { \

View file

@ -315,11 +315,11 @@ linux_dutil_getRegValues( XW_DUtilCtxt* duc, XWEnv xwe )
return results; return results;
} }
#ifdef DUTIL_TIMERS
typedef struct _TimerClosure { typedef struct _TimerClosure {
XW_DUtilCtxt* duc; XW_DUtilCtxt* duc;
DUtilTimerProc proc; TimerKey key;
void* closure;
size_t closureSize;
guint src; guint src;
} TimerClosure; } TimerClosure;
@ -327,35 +327,23 @@ static gint
timer_proc( gpointer data ) timer_proc( gpointer data )
{ {
TimerClosure* tc = (TimerClosure*)data; TimerClosure* tc = (TimerClosure*)data;
XP_LOGFF( "calling timer proc" ); XP_LOGFF( "calling dvc_onTimerFired()" );
(*tc->proc)( NULL_XWE, tc->closure, tc->closureSize ); dvc_onTimerFired( tc->duc, NULL_XWE, tc->key );
XP_LOGFF( "timer proc done" ); g_free( tc );
XP_FREEP( tc->duc->mpool, &tc->closure ); return G_SOURCE_REMOVE;
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;
} }
#ifdef DUTIL_TIMERS
static void static void
linux_dutil_setTimer( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 when, linux_dutil_setTimer( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 inWhenMS, TimerKey key )
DUtilTimerProc proc, void* closure, size_t closureSize )
{ {
XP_USE(xwe); /* I assume I'll need this on the Android side */ 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->duc = duc;
tc->closureSize = closureSize; tc->key = key;
tc->closure = XP_MALLOC( duc->mpool, closureSize );
XP_MEMCPY( tc->closure, closure, closureSize ); XP_LOGFF( "key: %d, inWhenMS: %d", key, inWhenMS );
tc->proc = proc; tc->src = g_timeout_add( inWhenMS, timer_proc, tc );
tc->src = g_timeout_add( when, timer_proc, tc );
LinDUtilCtxt* lduc = (LinDUtilCtxt*)duc; LinDUtilCtxt* lduc = (LinDUtilCtxt*)duc;
GSList** timers = &lduc->timers; GSList** timers = &lduc->timers;
@ -365,14 +353,15 @@ linux_dutil_setTimer( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 when,
} }
static gint static gint
findByProc( gconstpointer elemData, gconstpointer proc ) findByProc( gconstpointer elemData, gconstpointer keyp )
{ {
TimerClosure* tc = (TimerClosure*)elemData; 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 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 /* 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 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; LinDUtilCtxt* lduc = (LinDUtilCtxt*)duc;
GSList** timers = &lduc->timers; GSList** timers = &lduc->timers;
while ( !!*timers ) { while ( !!*timers ) {
GSList* elem = g_slist_find_custom( *timers, proc, findByProc ); GSList* elem = g_slist_find_custom( *timers, &key, findByProc );
if ( !elem ) { if ( !elem ) {
break; break;
} }
TimerClosure* tc = (TimerClosure*)elem->data;
*timers = g_slist_remove( *timers, elem ); *timers = g_slist_remove( *timers, elem );
g_source_remove( tc->src );
g_free( tc );
++count; ++count;
} }
XP_LOGFF( "removed %d timers", count ); XP_LOGFF( "removed %d timers", count );

View file

@ -399,7 +399,8 @@ mqttc_cleanup( LaunchParams* params )
storage->mosq = NULL; storage->mosq = NULL;
mosquitto_lib_cleanup(); 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_ASSERT( params->mqttConStorage == storage ); /* cheat */
XP_FREEP( params->mpool, &storage ); XP_FREEP( params->mpool, &storage );