rewrite mutex stuff to make timeout/asserting easier

This commit is contained in:
Eric House 2024-08-20 22:03:08 -07:00
parent db35adbada
commit 466abffc43
15 changed files with 157 additions and 88 deletions

View file

@ -417,7 +417,7 @@ comms_make( MPFORMAL XWEnv xwe, XW_UtilCtxt* util, XP_Bool isServer,
XP_U16 forceChannel ) XP_U16 forceChannel )
{ {
CommsCtxt* comms = (CommsCtxt*)XP_CALLOC( mpool, sizeof(*comms) ); CommsCtxt* comms = (CommsCtxt*)XP_CALLOC( mpool, sizeof(*comms) );
mtx_init( &comms->mutex, XP_TRUE ); MUTEX_INIT( &comms->mutex, XP_TRUE );
comms->util = util; comms->util = util;
comms->dutil = util_getDevUtilCtxt( util, xwe ); comms->dutil = util_getDevUtilCtxt( util, xwe );
#ifdef DEBUG #ifdef DEBUG
@ -587,7 +587,7 @@ comms_destroy( CommsCtxt* comms, XWEnv xwe )
util_clearTimer( comms->util, xwe, TIMER_COMMS ); util_clearTimer( comms->util, xwe, TIMER_COMMS );
END_WITH_MUTEX(); END_WITH_MUTEX();
mtx_destroy( &comms->mutex ); MUTEX_DESTROY( &comms->mutex );
XP_FREE( comms->mpool, comms ); XP_FREE( comms->mpool, comms );
} /* comms_destroy */ } /* comms_destroy */

View file

@ -28,6 +28,8 @@
# define RELCONST const # define RELCONST const
#endif #endif
#include <pthread.h>
#include "xptypes.h" #include "xptypes.h"
#ifndef EXTERN_C_START #ifndef EXTERN_C_START
@ -344,6 +346,14 @@ typedef struct _TrayTileSet {
TrayTile tiles[MAX_TRAY_TILES]; TrayTile tiles[MAX_TRAY_TILES];
} TrayTileSet; } TrayTileSet;
/* making this a struct in case I want to add e.g. a chain of holders */
typedef struct _MutexState {
pthread_mutex_t mutex;
#ifdef DEBUG
XP_U16 waitSecs;
#endif
} MutexState;
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
/* temporary debugging hack */ /* temporary debugging hack */

View file

@ -733,6 +733,7 @@ static void
delWSDatum( DLHead* elem, void* closure ) delWSDatum( DLHead* elem, void* closure )
{ {
XW_DUtilCtxt* dutil = (XW_DUtilCtxt*)closure; XW_DUtilCtxt* dutil = (XW_DUtilCtxt*)closure;
XP_USE(dutil); /* for release builds */
XP_FREEP( dutil->mpool, &elem ); XP_FREEP( dutil->mpool, &elem );
} }
@ -1178,8 +1179,8 @@ dvc_init( XW_DUtilCtxt* dutil, XWEnv xwe )
dc->webSendData = NULL; dc->webSendData = NULL;
dc->mWebSendKey = 0; dc->mWebSendKey = 0;
mtx_init( &dc->webSendMutex, XP_FALSE ); MUTEX_INIT( &dc->webSendMutex, XP_FALSE );
mtx_init( &dc->ackTimer.mutex, XP_FALSE ); MUTEX_INIT( &dc->ackTimer.mutex, XP_FALSE );
loadPhoniesData( dutil, xwe, dc ); loadPhoniesData( dutil, xwe, dc );
@ -1195,8 +1196,8 @@ dvc_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe )
DevCtxt* dc = freePhonyState( dutil, xwe ); DevCtxt* dc = freePhonyState( dutil, xwe );
freeWSState( dutil, dc ); freeWSState( dutil, dc );
mtx_destroy( &dc->webSendMutex ); MUTEX_DESTROY( &dc->webSendMutex );
mtx_destroy( &dc->ackTimer.mutex ); MUTEX_DESTROY( &dc->ackTimer.mutex );
XP_FREEP( dutil->mpool, &dc ); XP_FREEP( dutil->mpool, &dc );
} }

View file

@ -64,7 +64,7 @@ DictMgrCtxt*
dmgr_make( MPFORMAL_NOCOMMA ) dmgr_make( MPFORMAL_NOCOMMA )
{ {
DictMgrCtxt* dmgr = XP_CALLOC( mpool, sizeof(*dmgr) ); DictMgrCtxt* dmgr = XP_CALLOC( mpool, sizeof(*dmgr) );
mtx_init( &dmgr->mutex, XP_FALSE ); MUTEX_INIT( &dmgr->mutex, XP_FALSE );
MPASSIGN( dmgr->mpool, mpool ); MPASSIGN( dmgr->mpool, mpool );
return dmgr; return dmgr;
} }
@ -78,7 +78,7 @@ dmgr_destroy( DictMgrCtxt* dmgr, XWEnv xwe )
dict_unref( pair->dict, xwe ); dict_unref( pair->dict, xwe );
XP_FREEP( dmgr->mpool, &pair->key ); XP_FREEP( dmgr->mpool, &pair->key );
} }
mtx_destroy( &dmgr->mutex ); MUTEX_DESTROY( &dmgr->mutex );
XP_FREE( dmgr->mpool, dmgr ); XP_FREE( dmgr->mpool, dmgr );
} }
@ -87,7 +87,7 @@ dmgr_get( DictMgrCtxt* dmgr, XWEnv xwe, const XP_UCHAR* key )
{ {
const DictionaryCtxt* result = NULL; const DictionaryCtxt* result = NULL;
WITH_MUTEX( &dmgr->mutex ); WITH_MUTEX_CHECKED( &dmgr->mutex, 1 );
XP_S16 index = findFor( dmgr, key ); XP_S16 index = findFor( dmgr, key );
if ( 0 <= index ) { if ( 0 <= index ) {

View file

@ -85,7 +85,7 @@ p_dict_unref( const DictionaryCtxt* dict, XWEnv xwe
if ( 0 == _dict->refCount ) { if ( 0 == _dict->refCount ) {
/* There's a race here. If another thread locks the mutex we'll /* There's a race here. If another thread locks the mutex we'll
still destroy the dict (and the locked mutex!!!) PENDING */ still destroy the dict (and the locked mutex!!!) PENDING */
mtx_destroy( &_dict->mutex ); MUTEX_DESTROY( &_dict->mutex );
(*dict->destructor)( _dict, xwe ); (*dict->destructor)( _dict, xwe );
} }
} }
@ -1209,7 +1209,7 @@ dict_super_init( MPFORMAL DictionaryCtxt* dict )
dict->func_dict_edge_with_tile = dict_super_edge_with_tile; dict->func_dict_edge_with_tile = dict_super_edge_with_tile;
dict->func_dict_getShortName = dict_getName; dict->func_dict_getShortName = dict_getName;
mtx_init( &dict->mutex, XP_FALSE ); MUTEX_INIT( &dict->mutex, XP_FALSE );
} /* dict_super_init */ } /* dict_super_init */
void void

View file

@ -32,7 +32,6 @@
#include "dawg.h" #include "dawg.h"
#include "model.h" #include "model.h"
#include "mempool.h" #include "mempool.h"
#include "xwmutex.h"
#ifdef CPLUS #ifdef CPLUS
extern "C" { extern "C" {

View file

@ -27,6 +27,7 @@
#include "device.h" #include "device.h"
#include "stats.h" #include "stats.h"
#include "timers.h" #include "timers.h"
#include "xwmutex.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[],
@ -59,7 +60,7 @@ void
dutil_super_init( MPFORMAL XW_DUtilCtxt* dutil ) dutil_super_init( MPFORMAL XW_DUtilCtxt* dutil )
{ {
#ifdef XWFEATURE_KNOWNPLAYERS #ifdef XWFEATURE_KNOWNPLAYERS
mtx_init( &dutil->kpMutex, XP_FALSE ); MUTEX_INIT( &dutil->kpMutex, XP_FALSE );
#endif #endif
MPASSIGN( dutil->mpool, mpool ); MPASSIGN( dutil->mpool, mpool );

View file

@ -28,7 +28,6 @@
#include "vtabmgr.h" #include "vtabmgr.h"
#include "commstyp.h" #include "commstyp.h"
#include "nlityp.h" #include "nlityp.h"
#include "xwmutex.h"
#include "cJSON.h" #include "cJSON.h"
typedef enum { UNPAUSED, typedef enum { UNPAUSED,

View file

@ -25,6 +25,7 @@
#include "comms.h" #include "comms.h"
#include "dbgutil.h" #include "dbgutil.h"
#include "dllist.h" #include "dllist.h"
#include "xwmutex.h"
typedef struct _KnownPlayer { typedef struct _KnownPlayer {
DLHead links; DLHead links;

View file

@ -64,7 +64,7 @@ mpool_make( const XP_UCHAR* tag )
{ {
MemPoolCtx* result = (MemPoolCtx*)XP_PLATMALLOC( sizeof(*result) ); MemPoolCtx* result = (MemPoolCtx*)XP_PLATMALLOC( sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) ); XP_MEMSET( result, 0, sizeof(*result) );
mtx_init( &result->mutex, XP_TRUE ); MUTEX_INIT( &result->mutex, XP_TRUE );
mpool_setTag( result, tag ); mpool_setTag( result, tag );
return result; return result;
} /* mpool_make */ } /* mpool_make */
@ -160,7 +160,7 @@ mpool_destroy( MemPoolCtx* mpool )
#endif #endif
freeList( mpool->freeList ); freeList( mpool->freeList );
mtx_destroy( &mpool->mutex ); MUTEX_DESTROY( &mpool->mutex );
XP_PLATFREE( mpool ); XP_PLATFREE( mpool );
} /* mpool_destroy */ } /* mpool_destroy */

View file

@ -121,7 +121,7 @@ SMSProto*
smsproto_init( MPFORMAL XWEnv xwe, XW_DUtilCtxt* dutil ) smsproto_init( MPFORMAL XWEnv xwe, XW_DUtilCtxt* dutil )
{ {
SMSProto* state = (SMSProto*)XP_CALLOC( mpool, sizeof(*state) ); SMSProto* state = (SMSProto*)XP_CALLOC( mpool, sizeof(*state) );
mtx_init( &state->mutex, XP_FALSE ); MUTEX_INIT( &state->mutex, XP_FALSE );
state->dutil = dutil; state->dutil = dutil;
MPASSIGN( state->mpool, mpool ); MPASSIGN( state->mpool, mpool );
@ -157,7 +157,7 @@ smsproto_free( SMSProto* state )
} }
XP_ASSERT( !state->fromPhoneRecs ); /* above nulls this once empty */ XP_ASSERT( !state->fromPhoneRecs ); /* above nulls this once empty */
mtx_destroy( &state->mutex ); MUTEX_DESTROY( &state->mutex );
XP_FREEP( state->mpool, &state ); XP_FREEP( state->mpool, &state );
} }

View file

@ -18,13 +18,14 @@
*/ */
#include "stats.h" #include "stats.h"
#include "xwmutex.h"
#include "device.h" #include "device.h"
#include "xwstream.h" #include "xwstream.h"
#include "strutils.h" #include "strutils.h"
#include "dbgutil.h" #include "dbgutil.h"
#include "timers.h" #include "timers.h"
#include "xwmutex.h"
typedef struct StatsState { typedef struct StatsState {
XP_U32* statsVals; XP_U32* statsVals;
MutexState mutex; MutexState mutex;
@ -40,7 +41,7 @@ void
sts_init( XW_DUtilCtxt* dutil ) sts_init( XW_DUtilCtxt* dutil )
{ {
StatsState* ss = XP_CALLOC( dutil->mpool, sizeof(*ss) ); StatsState* ss = XP_CALLOC( dutil->mpool, sizeof(*ss) );
mtx_init( &ss->mutex, XP_TRUE ); MUTEX_INIT( &ss->mutex, XP_TRUE );
dutil->statsState = ss; dutil->statsState = ss;
} }
@ -49,7 +50,7 @@ sts_cleanup( XW_DUtilCtxt* dutil, XWEnv XP_UNUSED(xwe) )
{ {
StatsState* ss = dutil->statsState; StatsState* ss = dutil->statsState;
XP_ASSERT( !!ss ); XP_ASSERT( !!ss );
mtx_destroy( &ss->mutex ); MUTEX_DESTROY( &ss->mutex );
XP_FREEP( dutil->mpool, &ss->statsVals ); XP_FREEP( dutil->mpool, &ss->statsVals );
XP_FREEP( dutil->mpool, &ss ); XP_FREEP( dutil->mpool, &ss );
} }
@ -180,7 +181,7 @@ loadCounts( XW_DUtilCtxt* dutil, XWEnv xwe )
#ifdef DUTIL_TIMERS #ifdef DUTIL_TIMERS
static void static void
onStoreTimer( void* closure, XWEnv xwe, XP_Bool fired ) onStoreTimer( void* closure, XWEnv xwe, XP_Bool XP_UNUSED_DBG(fired) )
{ {
XP_LOGFF( "(fired: %s)", boolToStr(fired) ); XP_LOGFF( "(fired: %s)", boolToStr(fired) );
XW_DUtilCtxt* dutil = (XW_DUtilCtxt*)closure; XW_DUtilCtxt* dutil = (XW_DUtilCtxt*)closure;
@ -204,7 +205,10 @@ setStoreTimerLocked( XW_DUtilCtxt* dutil, XWEnv xwe )
if ( !ss->timerSet ) { if ( !ss->timerSet ) {
ss->timerSet = XP_TRUE; ss->timerSet = XP_TRUE;
XP_U32 inWhenMS = 5 * 1000; XP_U32 inWhenMS = 5 * 1000;
TimerKey key = tmr_set( dutil, xwe, inWhenMS, onStoreTimer, dutil ); #ifdef DEBUG
TimerKey key =
#endif
tmr_set( dutil, xwe, inWhenMS, onStoreTimer, dutil );
XP_LOGFF( "tmr_set() => %d", key ); XP_LOGFF( "tmr_set() => %d", key );
} else { } else {
XP_LOGFF( "timer already set" ); XP_LOGFF( "timer already set" );

View file

@ -47,7 +47,7 @@ tmr_init( XW_DUtilCtxt* dutil )
TimerMgrState* tms = XP_CALLOC( dutil->mpool, sizeof(*tms) ); TimerMgrState* tms = XP_CALLOC( dutil->mpool, sizeof(*tms) );
tms->dutil = dutil; tms->dutil = dutil;
dutil->timersState = tms; dutil->timersState = tms;
mtx_init( &tms->mutex, XP_TRUE ); MUTEX_INIT( &tms->mutex, XP_TRUE );
} }
void void
@ -56,7 +56,7 @@ tmr_cleanup( XW_DUtilCtxt* dutil, XWEnv xwe )
TimerMgrState* timersState = (TimerMgrState*)dutil->timersState; TimerMgrState* timersState = (TimerMgrState*)dutil->timersState;
XP_ASSERT( !!timersState ); XP_ASSERT( !!timersState );
clearPendings( dutil, xwe ); clearPendings( dutil, xwe );
mtx_destroy( &timersState->mutex ); MUTEX_DESTROY( &timersState->mutex );
XP_FREEP( dutil->mpool, &dutil->timersState ); XP_FREEP( dutil->mpool, &dutil->timersState );
} }
@ -85,7 +85,8 @@ tmr_set( XW_DUtilCtxt* dutil, XWEnv xwe, XP_U32 inWhen,
} }
static void static void
timerFired( XW_DUtilCtxt* dutil, XWEnv xwe, TimerState* timer, XP_Bool fired ) timerFired( XW_DUtilCtxt* XP_UNUSED_DBG(dutil), XWEnv xwe, TimerState* timer,
XP_Bool fired )
{ {
XP_LOGFF( "(timer=%p); key=%d", timer, timer->key ); XP_LOGFF( "(timer=%p); key=%d", timer, timer->key );
(*timer->proc)( timer->closure, xwe, fired ); (*timer->proc)( timer->closure, xwe, fired );

View file

@ -19,34 +19,102 @@
#include "xwmutex.h" #include "xwmutex.h"
#ifdef DEBUG
#define WAIT_ALL_SECS 3
typedef struct _WaitState {
const char* caller;
XP_U16 waitSecs;
} WaitState;
static void*
checkLockProc(void* closure)
{
WaitState* wsp = (WaitState*)closure;
sleep( wsp->waitSecs );
XP_LOGFF( "failed to get mutex in %d secs (caller: %s())",
wsp->waitSecs, wsp->caller );
XP_ASSERT(0);
return NULL;
}
void void
mtx_init( MutexState* mutex, XP_Bool recursive ) mtx_lock_prv( MutexState* state, XP_U16 waitSecs, const char* caller )
{
// XP_LOGFF( "(caller=%s, waitSecs=%d)", caller, waitSecs );
pthread_t waitThread;
WaitState ws = {
.waitSecs = 0 < waitSecs ? waitSecs : state->waitSecs,
.caller = caller,
};
if ( 0 < waitSecs ) {
(void)pthread_create( &waitThread, NULL, checkLockProc, &ws );
}
pthread_mutex_lock( &state->mutex );
if ( 0 < waitSecs ) {
(void)pthread_cancel(waitThread);
}
}
void
mtx_unlock_prv( MutexState* state, XP_U16 XP_UNUSED(waitSecs),
const char* XP_UNUSED(caller) )
{
// XP_LOGFF( "(caller=%s, waitSecs=%d)", caller, waitSecs );
pthread_mutex_unlock( &state->mutex );
}
#endif
void
mtx_init_prv( MutexState* mutex, XP_Bool recursive
#ifdef DEBUG
, XP_U16 waitSecs
#endif
)
{ {
pthread_mutexattr_t attr; pthread_mutexattr_t attr;
int ret = pthread_mutexattr_init(&attr); #ifdef DEBUG
int ret =
#endif
pthread_mutexattr_init(&attr);
XP_ASSERT(0 == ret); XP_ASSERT(0 == ret);
if ( recursive ) { if ( recursive ) {
ret = pthread_mutexattr_settype(&attr, #ifdef DEBUG
ret =
#endif
pthread_mutexattr_settype(&attr,
PTHREAD_MUTEX_RECURSIVE); PTHREAD_MUTEX_RECURSIVE);
XP_ASSERT(0 == ret); XP_ASSERT(0 == ret);
} }
#ifdef DEBUG
# ifdef WAIT_ALL_SECS
if ( waitSecs < WAIT_ALL_SECS ) {
waitSecs = WAIT_ALL_SECS;
}
# endif
mutex->waitSecs = waitSecs;
#endif
pthread_mutex_init( &mutex->mutex, &attr ); pthread_mutex_init( &mutex->mutex, &attr );
ret = pthread_mutexattr_destroy(&attr); #ifdef DEBUG
ret =
#endif
pthread_mutexattr_destroy(&attr);
XP_ASSERT(0 == ret); XP_ASSERT(0 == ret);
#ifdef DEBUG /* #ifdef DEBUG */
/* if ( recursive ) { */ /* if ( recursive ) { */
/* XP_LOGFF( "testing recursive call..." ); */ /* XP_LOGFF( "testing recursive call..." ); */
/* WITH_MUTEX( mutex ); */ /* WITH_MUTEX( mutex ); */
/* WITH_MUTEX( mutex ); */ /* WITH_MUTEX( mutex ); */
/* END_WITH_MUTEX(); */ /* END_WITH_MUTEX(); */
/* END_WITH_MUTEX(); */ /* END_WITH_MUTEX(); */
/* } */ /* } */
#endif /* #endif */
} }
void void
mtx_destroy( MutexState* mutex ) mtx_destroy_prv( MutexState* mutex )
{ {
pthread_mutex_destroy( &mutex->mutex ); pthread_mutex_destroy( &mutex->mutex );
} }

View file

@ -20,59 +20,44 @@
#ifndef _XWMUTEX_H_ #ifndef _XWMUTEX_H_
#define _XWMUTEX_H_ #define _XWMUTEX_H_
#include <pthread.h>
#include "xptypes.h" #include "xptypes.h"
#include "comtypes.h"
/* Making this a struct in case I want to add e.g. a chain of holders */
typedef struct _MutexState {
pthread_mutex_t mutex;
} MutexState;
#ifdef MUTEX_LOG_VERBOSE
# 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 ) { \
XP_LOGFF("took %lds to get mutex", _elapsed); \
} \
#define WITH_MUTEX_UNLOCK_DEBUG() \
time_t unlockTime = time(NULL); \
_elapsed = unlockTime-gotItTime; \
if ( 0 < _elapsed ) { \
XP_LOGFF("held mutex for %lds", _elapsed); \
} \
pthread_mutex_unlock(&_state->mutex); \
MUTEX_LOG( "released mutex %p", _state ); \
} \
#define WITH_MUTEX_LOCK_RELEASE(COMMS) { \
MutexState* _state = (STATEP); \
pthread_mutex_lock(&_state->mutex); \
#define WITH_MUTEX_UNLOCK_RELEASE() \
pthread_mutex_unlock(&_state->mutex); \
} \
#ifdef DEBUG #ifdef DEBUG
#define WITH_MUTEX WITH_MUTEX_LOCK_DEBUG
#define END_WITH_MUTEX WITH_MUTEX_UNLOCK_DEBUG void mtx_lock_prv(MutexState* state, XP_U16 waitSecs, const char* caller);
void mtx_unlock_prv(MutexState* state, XP_U16 waitSecs, const char* caller);
# define WITH_MUTEX_CHECKED(STATE, SECS) { \
MutexState* _state = (STATE); \
XP_U16 _waitSecs = (SECS); \
mtx_lock_prv(_state, _waitSecs, __func__)
# define WITH_MUTEX(STATE) WITH_MUTEX_CHECKED(STATE, 0)
# define END_WITH_MUTEX() mtx_unlock_prv(_state, _waitSecs, __func__); \
}
#else #else
#define WITH_MUTEX WITH_MUTEX_LOCK_RELEASE # define WITH_MUTEX(STATE) { \
#define END_WITH_MUTEX WITH_MUTEX_UNLOCK_RELEASE const pthread_mutex_t* _mutex = &(STATE)->mutex; \
pthread_mutex_lock((pthread_mutex_t*)_mutex)
# define WITH_MUTEX_CHECKED(STATE, IGNORE) WITH_MUTEX(STATE)
# define END_WITH_MUTEX() pthread_mutex_unlock((pthread_mutex_t*)_mutex); \
}
#endif #endif
void mtx_init( MutexState* mutex, XP_Bool recursive ); void mtx_init_prv( MutexState* mutex, XP_Bool recursive
void mtx_destroy( MutexState* mutex ); # ifdef DEBUG
, XP_U16 waitSecs
# endif
);
void mtx_destroy_prv( MutexState* mutex );
#ifdef DEBUG
# define MUTEX_INIT_CHECKED(STATE, RECURSIVE, WS) mtx_init_prv((STATE), (RECURSIVE), (WS))
# define MUTEX_INIT(STATE, RECURSIVE) MUTEX_INIT_CHECKED(STATE, RECURSIVE, 0)
#else
# define MUTEX_INIT(STATE, RECURSIVE) mtx_init_prv((STATE), (RECURSIVE))
# define MUTEX_INIT_CHECKED(STATE, RECURSIVE, WS) MUTEX_INIT((STATE), (RECURSIVE))
#endif
#define MUTEX_DESTROY(STATE) mtx_destroy_prv((STATE))
#endif #endif