I ported my fast reader-writer lock from C# to C for Process Hacker 2. Here it is.
#include <windows.h> #include <intrin.h> // Put this in a header file. typedef struct _PH_FAST_LOCK { ULONG Value; HANDLE ExclusiveWakeEvent; HANDLE SharedWakeEvent; } PH_FAST_LOCK, *PPH_FAST_LOCK; #define PH_LOCK_OWNED 0x1 #define PH_LOCK_EXCLUSIVE_WAKING 0x2 #define PH_LOCK_SHARED_OWNERS_SHIFT 2 #define PH_LOCK_SHARED_OWNERS_MASK 0x3ff #define PH_LOCK_SHARED_OWNERS_INC 0x4 #define PH_LOCK_SHARED_WAITERS_SHIFT 12 #define PH_LOCK_SHARED_WAITERS_MASK 0x3ff #define PH_LOCK_SHARED_WAITERS_INC 0x1000 #define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22 #define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3ff #define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000 #define PH_LOCK_EXCLUSIVE_MASK \ (PH_LOCK_EXCLUSIVE_WAKING | \ (PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT)) static ULONG PhLockSpinCount; // Call this method BEFORE using any of the other functions. VOID PhFastLockInitialization() { SYSTEM_INFO systemInfo; GetSystemInfo(&systemInfo); if (systemInfo.dwNumberOfProcessors > 1) PhLockSpinCount = 4000; else PhLockSpinCount = 0; } VOID PhInitializeFastLock( __out PPH_FAST_LOCK FastLock ) { FastLock->Value = 0; FastLock->ExclusiveWakeEvent = NULL; FastLock->SharedWakeEvent = NULL; } VOID PhDeleteFastLock( __inout PPH_FAST_LOCK FastLock ) { if (FastLock->ExclusiveWakeEvent) { CloseHandle(FastLock->ExclusiveWakeEvent); FastLock->ExclusiveWakeEvent = NULL; } if (FastLock->SharedWakeEvent) { CloseHandle(FastLock->SharedWakeEvent); FastLock->SharedWakeEvent = NULL; } } #ifdef _M_IX86 FORCEINLINE PVOID _InterlockedCompareExchangePointer( __inout PVOID volatile *Destination, __in PVOID Exchange, __in PVOID Comparand ) { return (PVOID)_InterlockedCompareExchange( (PLONG_PTR)Destination, (LONG_PTR)Exchange, (LONG_PTR)Comparand ); } FORCEINLINE PVOID _InterlockedExchangePointer( __inout PVOID volatile *Destination, __in PVOID Exchange ) { return (PVOID)_InterlockedExchange( (PLONG_PTR)Destination, (LONG_PTR)Exchange ); } #endif FORCEINLINE VOID PhpEnsureEventCreated( __inout PHANDLE Handle ) { HANDLE handle; if (*Handle != NULL) return; handle = CreateSemaphore(NULL, 0, MAXLONG, NULL); if (_InterlockedCompareExchangePointer( Handle, handle, NULL ) != NULL) { CloseHandle(handle); } } VOID PhAcquireFastLockExclusive( __inout PPH_FAST_LOCK FastLock ) { ULONG value; ULONG i = 0; while (TRUE) { value = FastLock->Value; if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))) { if (_InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_OWNED, value ) == value) break; } else if (i >= PhLockSpinCount) { PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent); if (_InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_EXCLUSIVE_WAITERS_INC, value ) == value) { if (WaitForSingleObject( FastLock->ExclusiveWakeEvent, INFINITE ) != WAIT_OBJECT_0) { // You might want to raise an exception here. } do { value = FastLock->Value; } while (_InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_OWNED - PH_LOCK_EXCLUSIVE_WAKING, value ) != value); break; } } i++; YieldProcessor(); } } VOID PhAcquireFastLockShared( __inout PPH_FAST_LOCK FastLock ) { ULONG value; ULONG i = 0; while (TRUE) { value = FastLock->Value; if (!(value & ( PH_LOCK_OWNED | (PH_LOCK_SHARED_OWNERS_MASK << PH_LOCK_SHARED_OWNERS_SHIFT) | PH_LOCK_EXCLUSIVE_MASK ))) { if (_InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC, value ) == value) break; } else if ( (value & PH_LOCK_OWNED) && ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 0 && !(value & PH_LOCK_EXCLUSIVE_MASK) ) { if (_InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_SHARED_OWNERS_INC, value ) == value) break; } else if (i >= PhLockSpinCount) { PhpEnsureEventCreated(&FastLock->SharedWakeEvent); if (_InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_SHARED_WAITERS_INC, value ) == value) { if (WaitForSingleObject( FastLock->SharedWakeEvent, INFINITE ) != WAIT_OBJECT_0) { // You might want to raise an exception here. } continue; } } i++; YieldProcessor(); } } VOID PhReleaseFastLockExclusive( __inout PPH_FAST_LOCK FastLock ) { ULONG value; while (TRUE) { value = FastLock->Value; if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK) { if (_InterlockedCompareExchange( &FastLock->Value, value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_EXCLUSIVE_WAITERS_INC, value ) == value) { ReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL); break; } } else { ULONG sharedWaiters; sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK; if (_InterlockedCompareExchange( &FastLock->Value, value & ~(PH_LOCK_OWNED | (PH_LOCK_SHARED_WAITERS_MASK << PH_LOCK_SHARED_WAITERS_SHIFT)), value ) == value) { if (sharedWaiters) ReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0); break; } } YieldProcessor(); } } VOID PhReleaseFastLockShared( __inout PPH_FAST_LOCK FastLock ) { ULONG value; while (TRUE) { value = FastLock->Value; if (((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 1) { if (_InterlockedCompareExchange( &FastLock->Value, value - PH_LOCK_SHARED_OWNERS_INC, value ) == value) break; } else if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK) { if (_InterlockedCompareExchange( &FastLock->Value, value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_SHARED_OWNERS_INC - PH_LOCK_EXCLUSIVE_WAITERS_INC, value ) == value) { ReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL); break; } } else { if (_InterlockedCompareExchange( &FastLock->Value, value - PH_LOCK_OWNED - PH_LOCK_SHARED_OWNERS_INC, value ) == value) break; } YieldProcessor(); } } BOOLEAN PhTryAcquireFastLockExclusive( __inout PPH_FAST_LOCK FastLock ) { ULONG value; value = FastLock->Value; if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)) return FALSE; return _InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_OWNED, value ) == value; } BOOLEAN PhTryAcquireFastLockShared( __inout PPH_FAST_LOCK FastLock ) { ULONG value; value = FastLock->Value; if (value & PH_LOCK_EXCLUSIVE_MASK) return FALSE; if (!(value & PH_LOCK_OWNED)) { return _InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC, value ) == value; } else if ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) { return _InterlockedCompareExchange( &FastLock->Value, value + PH_LOCK_SHARED_OWNERS_INC, value ) == value; } else { return FALSE; } }
Great.I really Appreciate it.
Well done. Any way you can contact me about a possible usage of this code?
Good job. Same as above, anyway you can contact me for using above code in my product? Please drop me an email, thanks