216 lines
5.9 KiB
C
216 lines
5.9 KiB
C
#include "ph7int.h"
|
|
#if defined(__WINNT__)
|
|
#include <Windows.h>
|
|
#else
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#if defined(PH7_ENABLE_THREADS)
|
|
#if defined(__WINNT__)
|
|
struct SyMutex {
|
|
CRITICAL_SECTION sMutex;
|
|
sxu32 nType; /* Mutex type,one of SXMUTEX_TYPE_* */
|
|
};
|
|
/* Preallocated static mutex */
|
|
static SyMutex aStaticMutexes[] = {
|
|
{{0}, SXMUTEX_TYPE_STATIC_1},
|
|
{{0}, SXMUTEX_TYPE_STATIC_2},
|
|
{{0}, SXMUTEX_TYPE_STATIC_3},
|
|
{{0}, SXMUTEX_TYPE_STATIC_4},
|
|
{{0}, SXMUTEX_TYPE_STATIC_5},
|
|
{{0}, SXMUTEX_TYPE_STATIC_6}
|
|
};
|
|
static BOOL winMutexInit = FALSE;
|
|
static LONG winMutexLock = 0;
|
|
|
|
static sxi32 WinMutexGlobaInit(void) {
|
|
LONG rc;
|
|
rc = InterlockedCompareExchange(&winMutexLock, 1, 0);
|
|
if(rc == 0) {
|
|
sxu32 n;
|
|
for(n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n) {
|
|
InitializeCriticalSection(&aStaticMutexes[n].sMutex);
|
|
}
|
|
winMutexInit = TRUE;
|
|
} else {
|
|
/* Someone else is doing this for us */
|
|
while(winMutexInit == FALSE) {
|
|
Sleep(1);
|
|
}
|
|
}
|
|
return SXRET_OK;
|
|
}
|
|
static void WinMutexGlobalRelease(void) {
|
|
LONG rc;
|
|
rc = InterlockedCompareExchange(&winMutexLock, 0, 1);
|
|
if(rc == 1) {
|
|
/* The first to decrement to zero does the actual global release */
|
|
if(winMutexInit == TRUE) {
|
|
sxu32 n;
|
|
for(n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n) {
|
|
DeleteCriticalSection(&aStaticMutexes[n].sMutex);
|
|
}
|
|
winMutexInit = FALSE;
|
|
}
|
|
}
|
|
}
|
|
static SyMutex *WinMutexNew(int nType) {
|
|
SyMutex *pMutex = 0;
|
|
if(nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE) {
|
|
/* Allocate a new mutex */
|
|
pMutex = (SyMutex *)HeapAlloc(GetProcessHeap(), 0, sizeof(SyMutex));
|
|
if(pMutex == 0) {
|
|
return 0;
|
|
}
|
|
InitializeCriticalSection(&pMutex->sMutex);
|
|
} else {
|
|
/* Use a pre-allocated static mutex */
|
|
if(nType > SXMUTEX_TYPE_STATIC_6) {
|
|
nType = SXMUTEX_TYPE_STATIC_6;
|
|
}
|
|
pMutex = &aStaticMutexes[nType - 3];
|
|
}
|
|
pMutex->nType = nType;
|
|
return pMutex;
|
|
}
|
|
static void WinMutexRelease(SyMutex *pMutex) {
|
|
if(pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE) {
|
|
DeleteCriticalSection(&pMutex->sMutex);
|
|
HeapFree(GetProcessHeap(), 0, pMutex);
|
|
}
|
|
}
|
|
static void WinMutexEnter(SyMutex *pMutex) {
|
|
EnterCriticalSection(&pMutex->sMutex);
|
|
}
|
|
static sxi32 WinMutexTryEnter(SyMutex *pMutex) {
|
|
#ifdef _WIN32_WINNT
|
|
BOOL rc;
|
|
/* Only WindowsNT platforms */
|
|
rc = TryEnterCriticalSection(&pMutex->sMutex);
|
|
if(rc) {
|
|
return SXRET_OK;
|
|
} else {
|
|
return SXERR_BUSY;
|
|
}
|
|
#else
|
|
return SXERR_NOTIMPLEMENTED;
|
|
#endif
|
|
}
|
|
static void WinMutexLeave(SyMutex *pMutex) {
|
|
LeaveCriticalSection(&pMutex->sMutex);
|
|
}
|
|
/* Export Windows mutex interfaces */
|
|
static const SyMutexMethods sWinMutexMethods = {
|
|
WinMutexGlobaInit, /* xGlobalInit() */
|
|
WinMutexGlobalRelease, /* xGlobalRelease() */
|
|
WinMutexNew, /* xNew() */
|
|
WinMutexRelease, /* xRelease() */
|
|
WinMutexEnter, /* xEnter() */
|
|
WinMutexTryEnter, /* xTryEnter() */
|
|
WinMutexLeave /* xLeave() */
|
|
};
|
|
PH7_PRIVATE const SyMutexMethods *SyMutexExportMethods(void) {
|
|
return &sWinMutexMethods;
|
|
}
|
|
#elif defined(__UNIXES__)
|
|
#include <pthread.h>
|
|
struct SyMutex {
|
|
pthread_mutex_t sMutex;
|
|
sxu32 nType;
|
|
};
|
|
static SyMutex *UnixMutexNew(int nType) {
|
|
static SyMutex aStaticMutexes[] = {
|
|
{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_1},
|
|
{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_2},
|
|
{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_3},
|
|
{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_4},
|
|
{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_5},
|
|
{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_6}
|
|
};
|
|
SyMutex *pMutex;
|
|
if(nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE) {
|
|
pthread_mutexattr_t sRecursiveAttr;
|
|
/* Allocate a new mutex */
|
|
pMutex = (SyMutex *)malloc(sizeof(SyMutex));
|
|
if(pMutex == 0) {
|
|
return 0;
|
|
}
|
|
if(nType == SXMUTEX_TYPE_RECURSIVE) {
|
|
pthread_mutexattr_init(&sRecursiveAttr);
|
|
pthread_mutexattr_settype(&sRecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
|
|
}
|
|
pthread_mutex_init(&pMutex->sMutex, nType == SXMUTEX_TYPE_RECURSIVE ? &sRecursiveAttr : 0);
|
|
if(nType == SXMUTEX_TYPE_RECURSIVE) {
|
|
pthread_mutexattr_destroy(&sRecursiveAttr);
|
|
}
|
|
} else {
|
|
/* Use a pre-allocated static mutex */
|
|
if(nType > SXMUTEX_TYPE_STATIC_6) {
|
|
nType = SXMUTEX_TYPE_STATIC_6;
|
|
}
|
|
pMutex = &aStaticMutexes[nType - 3];
|
|
}
|
|
pMutex->nType = nType;
|
|
return pMutex;
|
|
}
|
|
static void UnixMutexRelease(SyMutex *pMutex) {
|
|
if(pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE) {
|
|
pthread_mutex_destroy(&pMutex->sMutex);
|
|
free(pMutex);
|
|
}
|
|
}
|
|
static void UnixMutexEnter(SyMutex *pMutex) {
|
|
pthread_mutex_lock(&pMutex->sMutex);
|
|
}
|
|
static void UnixMutexLeave(SyMutex *pMutex) {
|
|
pthread_mutex_unlock(&pMutex->sMutex);
|
|
}
|
|
/* Export pthread mutex interfaces */
|
|
static const SyMutexMethods sPthreadMutexMethods = {
|
|
0, /* xGlobalInit() */
|
|
0, /* xGlobalRelease() */
|
|
UnixMutexNew, /* xNew() */
|
|
UnixMutexRelease, /* xRelease() */
|
|
UnixMutexEnter, /* xEnter() */
|
|
0, /* xTryEnter() */
|
|
UnixMutexLeave /* xLeave() */
|
|
};
|
|
PH7_PRIVATE const SyMutexMethods *SyMutexExportMethods(void) {
|
|
return &sPthreadMutexMethods;
|
|
}
|
|
#else
|
|
/* Host application must register their own mutex subsystem if the target
|
|
* platform is not an UNIX-like or windows systems.
|
|
*/
|
|
struct SyMutex {
|
|
sxu32 nType;
|
|
};
|
|
static SyMutex *DummyMutexNew(int nType) {
|
|
static SyMutex sMutex;
|
|
SXUNUSED(nType);
|
|
return &sMutex;
|
|
}
|
|
static void DummyMutexRelease(SyMutex *pMutex) {
|
|
SXUNUSED(pMutex);
|
|
}
|
|
static void DummyMutexEnter(SyMutex *pMutex) {
|
|
SXUNUSED(pMutex);
|
|
}
|
|
static void DummyMutexLeave(SyMutex *pMutex) {
|
|
SXUNUSED(pMutex);
|
|
}
|
|
/* Export the dummy mutex interfaces */
|
|
static const SyMutexMethods sDummyMutexMethods = {
|
|
0, /* xGlobalInit() */
|
|
0, /* xGlobalRelease() */
|
|
DummyMutexNew, /* xNew() */
|
|
DummyMutexRelease, /* xRelease() */
|
|
DummyMutexEnter, /* xEnter() */
|
|
0, /* xTryEnter() */
|
|
DummyMutexLeave /* xLeave() */
|
|
};
|
|
PH7_PRIVATE const SyMutexMethods *SyMutexExportMethods(void) {
|
|
return &sDummyMutexMethods;
|
|
}
|
|
#endif /* __WINNT__ */
|
|
#endif /* PH7_ENABLE_THREADS */ |