38 lines
1.1 KiB
C
38 lines
1.1 KiB
C
#pragma once
|
|
// ke_spinlock.h - spinlock for short, non-sleeping critical sections
|
|
// Uses MSVC interlocked intrinsics. Never hold across a scheduling boundary.
|
|
#include <stdint.h>
|
|
#include <intrin.h>
|
|
|
|
typedef struct SPINLOCK {
|
|
volatile long Locked;
|
|
} SPINLOCK;
|
|
|
|
#define SPINLOCK_INIT { 0 }
|
|
|
|
// Issue 1 Fix: Save EFLAGS, disable interrupts, and return old flags.
|
|
static __forceinline uintptr_t KeAcquireSpinlock(SPINLOCK* sl) {
|
|
uintptr_t flags = __readeflags();
|
|
_disable();
|
|
while (_InterlockedCompareExchange(&sl->Locked, 1, 0) != 0)
|
|
_mm_pause();
|
|
return flags;
|
|
}
|
|
|
|
// Issue 1 Fix: Restore EFLAGS upon release.
|
|
static __forceinline void KeReleaseSpinlock(SPINLOCK* sl, uintptr_t flags) {
|
|
_InterlockedExchange(&sl->Locked, 0);
|
|
__writeeflags(flags);
|
|
}
|
|
|
|
static __forceinline int KeTryAcquireSpinlock(SPINLOCK* sl, uintptr_t* outFlags) {
|
|
uintptr_t flags = __readeflags();
|
|
_disable();
|
|
if (_InterlockedCompareExchange(&sl->Locked, 1, 0) == 0) {
|
|
*outFlags = flags;
|
|
return 1;
|
|
}
|
|
__writeeflags(flags);
|
|
return 0;
|
|
}
|