8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 22:03:03 +01:00

More simple (and stable i hope) implementation of fast mutex for NT platform

This commit is contained in:
hvlad 2007-04-11 13:24:55 +00:00
parent 1781894590
commit 7213cfa90d
2 changed files with 64 additions and 119 deletions

View File

@ -189,7 +189,6 @@ typedef sh_mem *SH_MEM;
typedef struct _FAST_MUTEX_SHARED_SECTION
{
SLONG fInitialized;
SLONG lSpinLock;
SLONG lThreadsWaiting;
SLONG lAvailable;
#ifdef _DEBUG
@ -201,7 +200,7 @@ typedef struct _FAST_MUTEX
{
HANDLE hEvent;
HANDLE hFileMap;
ULONG lSpinCount;
SLONG lSpinCount;
volatile FAST_MUTEX_SHARED_SECTION* lpSharedInfo;
} FAST_MUTEX;

View File

@ -3372,28 +3372,6 @@ static const LPCSTR FAST_MUTEX_MAP_NAME = "%s_FM_MAP";
static const int DEFAULT_INTERLOCKED_SPIN_COUNT = 0;
static const int DEFAULT_INTERLOCKED_SPIN_COUNT_SMP = 200;
typedef WINBASEAPI BOOL (WINAPI *pfnSwitchToThread) ();
static inline BOOL _switchToThread()
{
static pfnSwitchToThread fnSwitchToThread = NULL;
static bool bInit = false;
if (!bInit)
{
HMODULE hLib = GetModuleHandle("kernel32.dll");
if (hLib) {
fnSwitchToThread = (pfnSwitchToThread) GetProcAddress(hLib, "SwitchToThread");
}
bInit = true;
}
if (fnSwitchToThread)
return (*fnSwitchToThread) ();
else
return FALSE;
}
// VC6 has the wrong declaration for the operating system function.
// MinGW as well
#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) || defined __GNUC__
@ -3403,99 +3381,6 @@ static inline BOOL _switchToThread()
#endif
static inline void lockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect, ULONG SpinCount)
{
while (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) != 0)
{
ULONG j = SpinCount;
while (j != 0)
{
if (lpSect->lSpinLock == 0)
goto next;
j--;
}
_switchToThread();
next:;
}
}
static inline bool tryLockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
{
return (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) == 0);
}
static inline void unlockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
{
InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 0);
}
static DWORD enterFastMutex(FAST_MUTEX* lpMutex, DWORD dwMilliseconds)
{
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
while (true)
{
DWORD dwResult;
if (dwMilliseconds == 0) {
if (!tryLockSharedSection(lpSect))
return WAIT_TIMEOUT;
}
else {
lockSharedSection(lpSect, lpMutex->lSpinCount);
}
if (lpSect->lAvailable > 0)
{
lpSect->lAvailable--;
#ifdef _DEBUG
lpSect->dwThreadId = GetCurrentThreadId();
#endif
unlockSharedSection(lpSect);
return WAIT_OBJECT_0;
}
#ifdef _DEBUG
if (lpSect->dwThreadId == GetCurrentThreadId())
DebugBreak();
#endif
if (dwMilliseconds == 0)
{
unlockSharedSection(lpSect);
return WAIT_TIMEOUT;
}
InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
unlockSharedSection(lpSect);
// TODO actual timeout can be of any length
dwResult = WaitForSingleObject(lpMutex->hEvent, dwMilliseconds);
InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));
if (dwResult != WAIT_OBJECT_0)
return dwResult;
}
}
static bool leaveFastMutex(FAST_MUTEX* lpMutex)
{
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
lockSharedSection(lpSect, lpMutex->lSpinCount);
if (lpSect->lAvailable >= 1)
{
unlockSharedSection(lpSect);
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
lpSect->lAvailable++;
if (lpSect->lThreadsWaiting)
SetEvent(lpMutex->hEvent);
unlockSharedSection(lpSect);
return true;
}
static inline void deleteFastMutex(FAST_MUTEX* lpMutex)
{
UnmapViewOfFile((FAST_MUTEX_SHARED_SECTION*)lpMutex->lpSharedInfo);
@ -3563,7 +3448,6 @@ static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAtt
{
if (dwLastError != ERROR_ALREADY_EXISTS)
{
lpMutex->lpSharedInfo->lSpinLock = 0;
lpMutex->lpSharedInfo->lThreadsWaiting = 0;
lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
@ -3571,7 +3455,7 @@ static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAtt
else
{
while (!lpMutex->lpSharedInfo->fInitialized)
_switchToThread();
Sleep(0);
}
SetLastError(dwLastError);
@ -3644,6 +3528,68 @@ static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
lpMutex->lSpinCount = SpinCount;
}
static inline bool tryEnterFastMutex(FAST_MUTEX* lpMutex)
{
bool bLocked = false;
SLONG dwSpinCount = lpMutex->lSpinCount;
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
do
{
bLocked =
(InterlockedCompareExchange(FIX_TYPE(&lpSect->lAvailable), 0, 1) == 1);
} while (!bLocked && (dwSpinCount-- > 0));
return bLocked;
}
DWORD enterFastMutex(FAST_MUTEX* lpMutex, DWORD dwMilliseconds)
{
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
while (true)
{
if (tryEnterFastMutex(lpMutex)) {
return WAIT_OBJECT_0;
}
else if (!dwMilliseconds) {
return WAIT_TIMEOUT;
}
InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
const DWORD res = WaitForSingleObject(lpMutex->hEvent, dwMilliseconds);
InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));
if (res != WAIT_OBJECT_0)
return res;
if (InterlockedCompareExchange(FIX_TYPE(&lpSect->lAvailable), 0, 1) == 1) {
return WAIT_OBJECT_0;
}
else if (dwMilliseconds != INFINITE) {
return WAIT_TIMEOUT;
}
}
}
static bool leaveFastMutex(FAST_MUTEX* lpMutex)
{
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
if (InterlockedCompareExchange(FIX_TYPE(&lpSect->lAvailable), 1, 0) != 0)
{
gds__log("bug in leaveFastMutex");
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
if (lpSect->lThreadsWaiting)
SetEvent(lpMutex->hEvent);
return true;
}
int ISC_mutex_init(MTX mutex, const TEXT* mutex_name)
{