mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 04:43:03 +01:00
More simple (and stable i hope) implementation of fast mutex for NT platform
This commit is contained in:
parent
1781894590
commit
7213cfa90d
@ -189,7 +189,6 @@ typedef sh_mem *SH_MEM;
|
|||||||
typedef struct _FAST_MUTEX_SHARED_SECTION
|
typedef struct _FAST_MUTEX_SHARED_SECTION
|
||||||
{
|
{
|
||||||
SLONG fInitialized;
|
SLONG fInitialized;
|
||||||
SLONG lSpinLock;
|
|
||||||
SLONG lThreadsWaiting;
|
SLONG lThreadsWaiting;
|
||||||
SLONG lAvailable;
|
SLONG lAvailable;
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -201,7 +200,7 @@ typedef struct _FAST_MUTEX
|
|||||||
{
|
{
|
||||||
HANDLE hEvent;
|
HANDLE hEvent;
|
||||||
HANDLE hFileMap;
|
HANDLE hFileMap;
|
||||||
ULONG lSpinCount;
|
SLONG lSpinCount;
|
||||||
volatile FAST_MUTEX_SHARED_SECTION* lpSharedInfo;
|
volatile FAST_MUTEX_SHARED_SECTION* lpSharedInfo;
|
||||||
} FAST_MUTEX;
|
} FAST_MUTEX;
|
||||||
|
|
||||||
|
@ -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 = 0;
|
||||||
static const int DEFAULT_INTERLOCKED_SPIN_COUNT_SMP = 200;
|
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.
|
// VC6 has the wrong declaration for the operating system function.
|
||||||
// MinGW as well
|
// MinGW as well
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) || defined __GNUC__
|
#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) || defined __GNUC__
|
||||||
@ -3403,99 +3381,6 @@ static inline BOOL _switchToThread()
|
|||||||
#endif
|
#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)
|
static inline void deleteFastMutex(FAST_MUTEX* lpMutex)
|
||||||
{
|
{
|
||||||
UnmapViewOfFile((FAST_MUTEX_SHARED_SECTION*)lpMutex->lpSharedInfo);
|
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)
|
if (dwLastError != ERROR_ALREADY_EXISTS)
|
||||||
{
|
{
|
||||||
lpMutex->lpSharedInfo->lSpinLock = 0;
|
|
||||||
lpMutex->lpSharedInfo->lThreadsWaiting = 0;
|
lpMutex->lpSharedInfo->lThreadsWaiting = 0;
|
||||||
lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
|
lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
|
||||||
InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
|
InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
|
||||||
@ -3571,7 +3455,7 @@ static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAtt
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (!lpMutex->lpSharedInfo->fInitialized)
|
while (!lpMutex->lpSharedInfo->fInitialized)
|
||||||
_switchToThread();
|
Sleep(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLastError(dwLastError);
|
SetLastError(dwLastError);
|
||||||
@ -3644,6 +3528,68 @@ static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
|
|||||||
lpMutex->lSpinCount = 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)
|
int ISC_mutex_init(MTX mutex, const TEXT* mutex_name)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user