Haven't gotten round to compiling this since I've got cleanup to do in the original file it existed (linker will complain of redefined symbols otherwise) however I'm curious to know if anyone can see any potential issues (all the paw* types just map to printf equivs like %d, %jd etc, just ignore the paw prefix to understand which it is).
Code:
#include "rawpaw.h"
static pawjd tid = -1;
static pawd locks = 0;
static pawd mutexcount = 0;
#define MUTICES_PER_ALLOC 32
#ifdef PAW_API_MSW
typedef HANDLE sysmtx_t;
#else
typedef pthread_mutex_t sysmtx_t;
#endif
static sysmtx_t _shared_mutex, *shared_mutex = NULL;
typedef struct _mutex_t
{
bool taken;
pawjd tid;
paws name;
pawd locks;
} mutex_t;
mutex_t *_mutices = NULL;
mutex_t *mutices = NULL;
#ifdef PAW_API_MSW
static void rawpaw__free_mutex() { ReleaseMutex( _shared_mutex ); }
static void rawpaw__lock_mutex()
{ WaitForSingleObject( _shared_mutex, INFINITE ); }
static void rawpaw__term_mutex()
{ CloseHandle( _shared_mutex ); _shared_mutex = NULL; }
static sysmtx_t* rawpaw__init_mutex()
{
_shared_mutex = CreateMutex(NULL,FALSE,NULL);
return _shared_mutex ? &_shared_mutex : NULL;
}
#else
static void rawpaw__free_mutex() { pthread_mutex_unlock( &_shared_mutex ); }
static void rawpaw__lock_mutex() { pthread_mutex_lock( &_shared_mutex ); }
static void rawpaw__shut_mutex() { pthread_mutex_destroy( &_shared_mutex ); }
static sysmtx_t* rawpaw__init_mutex()
{
sysmtx_t *mtx = &_shared_mutex;
return (pthread_mutex_create( mtx, NULL ) == 0) ? mtx : NULL;
}
#endif
RAWPAW_API void rawpaw_free_mutex() { rawpaw__free_mutex(); }
RAWPAW_API pawd rawpaw_lock_mutex()
{
rawpaw__lock_mutex();
if ( !mutices )
{
rawpaw__free_mutex();
return EADDRNOTAVAIL;
}
return 0;
}
void rawpaw_shut_mutex()
{
pawd i = 0, n = 0;
/* Signal that the mutices are going to be removed */
rawpaw__lock_mutex();
mutices = NULL;
rawpaw__free_mutex();
/* Wait until all threads have released their mutices */
while ( n < mutexcount )
{
paw_yield();
rawpaw__lock_mutex();
for ( i = 0, n = 0; i < mutexcount; n += _mutices[i++].taken );
rawpaw__free_mutex();
}
/* No more data races possible */
mutexcount = 0;
shared_mutex = NULL;
_mutices = pawdel( _mutices );
rawpaw__shut_mutex( _shared_mutex );
}
pawd rawpaw_init_mutex()
{
if ( shared_mutex )
return EALREADY;
if ( pawgetid() != pawgetmainid() )
return EACCES;
errno = 0;
_mutices = pawgetUD( sizeof(mutex_t) * MUTICES_PER_ALLOC );
if ( !_mutices )
return errno;
errno = 0;
shared_mutex = rawpaw__init_mutex();
if ( !shared_mutex )
{
pawd err = errno;
pawdel(_mutices);
return err;
}
mutices = _mutices;
mutexcount = MUTICES_PER_ALLOC;
return 0;
}
RAWPAW_API pawmtx pawmtx_create()
{
pawd err = rawpaw_lock_mutex(), i = 0;
pawzd old = 0, nxt = 0;
if ( err )
{
errno = err;
return -1;
}
for ( i = 0; i < mutexcount; ++i )
{
if ( !(mutices[i].taken) )
{
mutices[i].taken = 1;
rawpaw_free_mutex();
return i;
}
}
old = sizeof(mutex_t) * mutexcount;
nxt = sizeof(mutex_t) * (mutexcount + MUTICES_PER_ALLOC);
mutices = pawget( _mutices, nxt );
if ( !mutices )
{
rawpaw_free_mutex();
mutices = _mutices;
return -1;
}
_mutices = mutices;
mutices[i].tid = -1;
mutices[i].name = "";
mutices[i].locks = 0;
mutices[i].taken = 1;
rawpaw_free_mutex();
return i;
}
RAWPAW_API void pawmtx_delete( pawmtx mtx )
{
if ( mtx < 0 )
return;
if ( !shared_mutex )
{
/* Mutex was already released allowing shared mutex to be released,
* in other words you've called this function on the same mutex 2 or
* more times, that should NEVER happen. */
pawRaise(PAW_E_SIGNAL_SEGVEC);
exit(EXIT_FAILURE);
return;
}
rawpaw__lock_mutex();
if ( mtx < mutexcount )
{
mutex_t *mutex = _mutices + mtx;
if ( mutex->tid == pawgetid() || mutex->tid < 0 )
{
mutex->name = NULL;
mutex->locks = 0;
mutex->taken = 0;
mutex->tid = -1;
}
}
rawpaw__free_mutex();
}
RAWPAW_API void pawmtx_free( pawmtx mtx )
{
pawd err = rawpaw_lock_mutex();
if ( err )
return;
if ( mtx < 0 || mtx >= mutexcount || mutices[mtx].tid != pawgetid() )
{
rawpaw_free_mutex();
return;
}
mutices[mtx].locks--;
if ( mutices[mtx].locks < 1 )
mutices[mtx].tid = -1;
rawpaw_free_mutex();
}
RAWPAW_API pawd pawmtx_lock( pawmtx mtx, pawjd wait )
{
pawd err = 0;
pawjd tid = pawgetid();
pawjd tics = 0, prev = clock(), next = 0;
while ( wait < 0 || tics < wait )
{
err = rawpaw_lock_mutex();
if ( err )
return err;
if ( mtx < 0 || mtx >= mutexcount || !(mutices[mtx].taken) )
{
rawpaw_free_mutex();
return -1;
}
if ( mutices[mtx].tid < 0 )
{
mutices[mtx].tid = tid;
rawpaw__free_mutex();
return 0;
}
rawpaw__free_mutex();
next = clock();
tics += next - prev;
prev = next;
}
return ETIMEDOUT;
}