mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-15 08:47:56 +01:00
add generic timers (with dutil component for scheduling)
This commit is contained in:
parent
ad651c6cba
commit
f406757fb2
13 changed files with 324 additions and 58 deletions
|
@ -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 = \
|
||||||
|
|
|
@ -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 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 ) \
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
166
xwords4/common/timers.c
Normal 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
40
xwords4/common/timers.h
Normal 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
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) { \
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
Loading…
Add table
Reference in a new issue