CPLMutex *CPLCreateMutex()
{
unsigned char *pabyMutex = static_cast<unsigned char *>(malloc(4));
if( pabyMutex == nullptr )
return nullptr;
pabyMutex[0] = 1;
pabyMutex[1] = 'r';
pabyMutex[2] = 'e';
pabyMutex[3] = 'd';
return (CPLMutex *) pabyMutex;
}
int CPLCreateOrAcquireMutexEx( CPLMutex **phMutex, double dfWaitInSeconds,
int nOptions )
{
bool bSuccess = false;
// Ironically, creation of this initial mutex is not threadsafe
// even though we use it to ensure that creation of other mutexes
// is threadsafe.
if( hCOAMutex == nullptr )
{
hCOAMutex = CPLCreateMutex();
if( hCOAMutex == nullptr )
{
*phMutex = nullptr;
return FALSE;
}
}
else
{
CPLAcquireMutex( hCOAMutex, dfWaitInSeconds );
}
if( *phMutex == nullptr )
{
*phMutex = CPLCreateMutexEx( nOptions );
bSuccess = *phMutex != nullptr;
CPLReleaseMutex( hCOAMutex );
}
else
{
CPLReleaseMutex( hCOAMutex );
bSuccess = CPL_TO_BOOL(CPLAcquireMutex( *phMutex, dfWaitInSeconds ));
}
return bSuccess;
}
CPLMutexHolder::CPLMutexHolder( CPLMutex **phMutex,
double dfWaitInSeconds,
const char *pszFileIn,
int nLineIn,
int nOptions ) :
hMutex(nullptr),
pszFile(pszFileIn),
nLine(nLineIn)
{
if( phMutex == nullptr )
{
fprintf( stderr, "CPLMutexHolder: phMutex )) NULL !\n" );
hMutex = nullptr;
return;
}
#ifdef DEBUG_MUTEX
// There is no way to use CPLDebug() here because it works with
// mutexes itself so we will fall in infinite recursion.
// fprintf() will do the job right.
fprintf( stderr,
"CPLMutexHolder: Request %p for pid %ld at %d/%s.\n",
*phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile );
#else
// TODO(schwehr): Find a better way to do handle this.
(void)pszFile;
(void)nLine;
#endif
if( !CPLCreateOrAcquireMutexEx( phMutex, dfWaitInSeconds, nOptions ) )
{
fprintf( stderr, "CPLMutexHolder: Failed to acquire mutex!\n" );
hMutex = nullptr;
}
else
{
#ifdef DEBUG_MUTEX
fprintf( stderr,
"CPLMutexHolder: Acquired %p for pid %ld at %d/%s.\n",
*phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile );
#endif
hMutex = *phMutex;
}
}
CPLMutexHolder::~CPLMutexHolder()
{
if( hMutex != nullptr )
{
#ifdef DEBUG_MUTEX
fprintf( stderr,
"~CPLMutexHolder: Release %p for pid %ld at %d/%s.\n",
hMutex, static_cast<long>(CPLGetPID()), nLine, pszFile );
#endif
CPLReleaseMutex( hMutex );
}
}
void CPLReleaseMutex( CPLMutex *hMutex )
{
unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
&& pabyMutex[3] == 'd' );
if( pabyMutex[0] < 1 )
CPLDebug( "CPLMultiProc",
"CPLReleaseMutex() called on mutex with %d as ref count!",
pabyMutex[0] );
pabyMutex[0] -= 1;
}